2015-02-24 12 views
6

Stavo leggendo su come la proprietà del prototipo Javascript funziona con l'ereditarietà e poi ho iniziato a consultare il codice Angular.js e ho trovato alcune domande.Perché assegnare qualcosa a Something.prototype.constructor?

Prima di tutto, ho letto che la proprietà prototype punta a un oggetto che ha una proprietà "costruttore" che punta alla funzione originale utilizzata per creare l'oggetto. Così, per esempio:

// This is the constructor 
function Shape() { 
    this.position = 1; 
} 

// The constructor points back to the original function we defined 
Shape.protoype.constructor == Shape; 

Il prototipo contiene anche tutti gli altri metodi o proprietà che sono state definite su di essa da noi o dal linguaggio Javascript per sé, e questi sono condivisi da tutte le istanze dell'oggetto. Se vuoi che un oggetto chiamato Square erediti da Shape devi impostare il prototipo di Square uguale a una nuova istanza di Shape perché la proprietà interna [[prototype]] di Square.prototype viene impostata sul valore dell'oggetto pubblico della proprietà Shape.prototype .

function Square() {} 
Square.prototype = new Shape(); 
var square = new Square(); 
square.position; // This will output 1 

Tutto questo ha senso per me.

Tuttavia, il codice Angular.js di cui ho una domanda sembra essere correlato a tutto ciò ma fa qualcosa che non capisco. Non sembra che abbia a che fare con l'ereditarietà, quindi posso capire perché ci sarebbero delle differenze, ma sono solo curioso di sapere perché l'hanno scritto come hanno fatto.

All'interno di Angular.js, vi è un oggetto HashMap e un oggetto Lexer, ma sono definiti in modo diverso ma sembrano essere istanziati e utilizzati nello stesso modo. Il costruttore Lexer viene prima definito e quindi imposta il prototipo su un oggetto letterale contenente metodi che devono essere condivisi da tutte le istanze del Lexer. Tutto ciò ha senso. Quello che non capisco è il motivo per cui specificano la proprietà "costruttore" e la impostano solo su "Lexer" quando non lo sono per HashMap di seguito.

var Lexer = function(options) { 
    this.options = options; 
}; 

// Notice they specify Lexer as the constructor even though they don't for HashMap below 
Lexer.prototype = { 
    constructor: Lexer, 
    lex: function(text) { ... }, 
    is: function(ch, chars) { ... }, 
    peek: function(i) { ... }, 
    isNumber: function(ch) { ... }, 
    isWhitespace: function(ch) { ... }, 
    isIdent: function(ch) { ... }, 
    isExpOperator: function(ch) { ... }, 
    throwError: function(error, start, end) { ... }, 
    readNumber: function() { ... }, 
    readIdent: function() { ... }, 
    readString: function(quote) { ... } 
}; 

Poi, se si guarda il codice HashMap, fanno la stessa cosa, tranne che non specificano la proprietà constructor. Perchè è questo? Sembra funzionare esattamente allo stesso modo, e ho provato che il costruttore viene ancora chiamato.

// The HashMap Constructor 
function HashMap(array, isolatedUid) { 
    if (isolatedUid) { 
     var uid = 0; 
     this.nextUid = function() { 
      return ++uid; 
     }; 
    } 
    forEach(array, this.put, this); 
} 

HashMap.prototype = { 
    put: function(key, value) { ... }, 
    get: function(key) { ... }, 
    remove: function(key) { ... } 
}; 

Così è la proprietà constructor facoltativa quando non v'è alcuna eredità, così forse una persona ha scritto il Lexer e un altro la HashMap e uno ha deciso di indicare il costruttore?

+0

vedere anche [Definizione di un prototipo di Javascript] (http://stackoverflow.com/q/17474390/1048572) – Bergi

+0

@Bergi Grazie, questo aiuta. – Triad

risposta

8

Per impostazione predefinita, ogni prototipo ha una proprietà constructor che fa riferimento alla funzione a cui "appartiene".

function A() { 
 
} 
 

 
console.log(A.prototype.constructor === A); // true

Se si sovrascrive un prototipo nella sua interezza con un oggetto letterale o con qualche altro prototipo costruito, questo valore constructor sarà ottenere spazzato via ed essere lasciato indefinito o con qualche altro valore.

function A() { 
 
} 
 
A.prototype = { 
 
    greeting: "Hello!" 
 
}; 
 

 
console.log(A.prototype.constructor === A); // false

La proprietà prototype constructor non è necessario in modo che il costruttore per funzionare correttamente, ma la gente spesso riassegnare prototype.constructor al suo valore iniziale, al fine di mantenere la coerenza, e questo è quello che stanno vedendo per Lexer.

considerare:

function A() { 
 
} 
 

 
function B() { 
 
} 
 

 
B.prototype = Object.create(A.prototype); 
 

 
var b = new B(); 
 

 
console.log(b.constructor === A); // true 
 
console.log(b.constructor === B); // false 
 

 
B.prototype.constructor = B; 
 

 
console.log(b.constructor === A); // false 
 
console.log(b.constructor === B); // true

Si può solo speculare sul motivo per cui questo è stato lasciato fuori per HashMap. Dubito che sia stato fatto per una buona ragione e potrebbe essere stato solo una svista.

+0

Grazie per averlo chiarito. Mi sento un po 'stupido per non averlo visto, ma lo stavo guardando in modo diverso prima perché ero confuso dal motivo per cui hanno messo "costruttore: Lexer" piuttosto che "costruttore: nuovo Lexer()", ma ora vedo perché non ha senso affatto. È SubConstructor.prototype = new Constructor() che dovrebbe avere la parola chiave "new" che assegnerà automaticamente la proprietà "SubConstructor.prototype.constructor" a "Constructor", che è uno scenario diverso da quello Angular sopra. – Triad

+1

@Triad Sì, è corretto. Ricorda che l'uso di 'SubConstructor.prototype = new Constructor()' per creare prototipi è ormai una pratica obsoleta. Al giorno d'oggi sarebbe 'SubConstructor.prototype = Object.create (Constructor.prototype);' – JLRishe

+0

Ah, buono a sapersi, grazie ancora. – Triad

Problemi correlati