2014-12-20 12 views
14

Provo ad estendere JavaScript Math. Ma una cosa mi ha sorpreso.L'estensione dell'oggetto Math tramite il prototipo non funziona

quando ho cercato di estenderlo da prototype

Math.prototype.randomBetween = function (a, b) { 
    return Math.floor(Math.random() * (b - a + 1) + a); 
}; 

In console ho errore 'Can not impostare la proprietà 'CasualeTra' undefined' ...

Ma se io asigne questa funzione per Math.__proto__

Math.__proto__.randomBetween = function (a, b) { 
    return Math.floor(Math.random() * (b - a + 1) + a); 
}; 

Quindi tutto funziona correttamente.

Qualcuno può spiegarmi perché funziona in questo modo? Apprezzo qualsiasi aiuto.

risposta

24

Math non è un costruttore, in modo da non avere prototype proprietà:

new Math(); // TypeError: Math is not a constructor 

Invece, è sufficiente aggiungere il metodo per Math se stesso come un own property:

Math.randomBetween = function (a, b) { 
    return Math.floor(Math.random() * (b - a + 1) + a); 
}; 

Il tuo approccio con __proto__ funziona perché, dal Math è un'istanza ObjectObject.prototype.

Ma poi si nota che si aggiunge il metodo randomBetween a tutti gli oggetti, non solo a Math. Questo può essere problematico, ad esempio quando si iterano oggetti con un ciclo for...in.

+0

@GeorgeJempty Perché non ti piace la "proprietà"? – Oriol

+0

@GeorgeJempty una "propria proprietà" in JavaScript è una proprietà che esiste direttamente su un particolare oggetto (al contrario di uno che viene ereditato tramite la catena del prototipo). Forse sarebbe più semplice da guardare se ci fossero delle virgolette o fossero in corsivo? – JLRishe

+0

Grazie per i chiarimenti, le virgolette potrebbero essere d'aiuto, altrimenti sembrerebbe un inglese storpiato –

3

Per citare this answer:

Alcune implementazioni JavaScript consentono l'accesso diretto alla [[Prototype]] proprietà, ad esempio tramite una proprietà non standard di nome __proto__. In generale, è possibile impostare il prototipo di un oggetto solo durante la creazione dell'oggetto: se si crea un nuovo oggetto tramite la nuova Func(), la proprietà [[Prototype]] dell'oggetto verrà impostata sull'oggetto a cui fa riferimento Func.prototype.

La ragione per cui non è possibile assegnare al suo prototipo utilizzando .prototype è perché l'oggetto Math è già stato creato.

Fortunatamente per noi, possiamo assegnare nuove proprietà all'oggetto Math semplicemente usando:

Math.myFunc = function() { return true }; 

Nel tuo caso, questo sarebbe:

Math.randomBetween = function(...) { ... }; 
+0

Per essere onesti tanto quanto odio il '__proto__', da allora è stato standardizzato e funziona su tutti i browser moderni. –

1

Ecco perché c'è Math è un oggetto , non a function.

In javascript, un function è l'equivalente approssimativo di una classe in linguaggi orientati agli oggetti. prototype è una proprietà speciale che consente di aggiungere metodi di istanza a questa classe .Quando si desidera estendere tale classe, si utilizza prototype e "funziona solo".

Ora pensiamo a ciò che è Math. Non si crea mai un oggetto matematico, si usano solo i suoi metodi. In realtà, non ha senso creare due diversi oggetti Math, perché Math funziona sempre allo stesso modo! In altre parole, l'oggetto Math in javascript è solo un modo conveniente per raggruppare insieme una serie di funzioni matematiche pre-scritte. È come un dizionario di matematica comune.

Vuoi aggiungere qualcosa a quel gruppo? Basta aggiungere una proprietà alla collezione! Ecco due semplici modi per farlo.

Math.randomBetween = function() { ... } 
Math["randomBetween"] = function() {... } 

L'utilizzo del secondo modo rende un po 'più ovvio che si tratta di un insieme di dizionari, ma entrambi fanno la stessa cosa.

0
var MyMath = Object.create(Math); // empty object with prototype Math 

MyMath.randomBetween = function (a, b) { 
    return this.floor(this.random() * (b - a + 1) + a); 
}; 

typeof(MyMath);     // object 
Object.getPrototypeOf(MyMath); // Math 
MyMath.PI;      // 3.14... 
MyMath.randomBetween(0, 10); // exactly that 
  • l'oggetto Math è il prototipo del nuovo MyMath oggetto
  • MyMath ha accesso a tutte le funzionalità di Math
  • puoi aggiungere la tua funzionalità personalizzate a MyMath senza manipolare Math
  • all'interno metodi personalizzati, utilizzare la parola chiave this per fare riferimento alla funzionalità Math

Non ci sono Monkey Patching con questo approccio. Questo è il modo migliore per estendere JavScript Math. Non c'è bisogno di ripetere le spiegazioni dalle altre risposte.

Problemi correlati