2015-12-08 18 views
5

Così sto prototipo utilizzando JavaScript di apprendimento, e ha cercato un po 'di codice:risultato indefinito utilizzando prototipo [javascript]

function Employee(name) { this.name= name; } 
var m = new Employee("Bob"); 
var working= { isWorking: true }; 
Employee.prototype = working; 
alert(m.isWorking); 

Purtroppo, ricevo un messaggio di non definito, invece che il vero valore. C'è una ragione per questo risultato?

Ho effettuato diversi test. Ho concluso che la riassegnazione dell'oggetto prototipo fa sì che eventuali istanze create in precedenza della classe Employee non siano in grado di accedere a nessuna proprietà trovata all'interno del prototipo appena assegnato. È accurato?

+3

Quando si crea un'istanza prende un riferimento al prototipo del costruttore al momento. Se sostituisci il prototipo in un secondo momento, le istanze esistenti non lo rifletteranno. Una volta creata un'istanza, è generalmente previsto che estenderai il prototipo anziché sostituirlo. –

+5

Il riferimento dell'istanza all'oggetto prototipo è impostato in fase di costruzione (ovvero la riga con 'new'). La modifica dell'intero oggetto proprietà 'Foo.prototype' non cambierà questo riferimento dopo l'istanza. Tuttavia, le modifiche all'oggetto 'Foo.prototype' _will_ possono essere viste (poiché si tratta dello stesso oggetto), quindi ad es. se invece hai fatto 'Employee.prototype.isWorking = true;', vedresti cosa ti aspetti –

+0

Per ulteriori informazioni, questa è un'eccellente riduzione dell'ereditarietà del prototipo: http://markdalgleish.com/2012/10/a -touch-of-class-inheritance-in-javascript/ – br3nt

risposta

1

Prima di tutto, è stata creata un'istanza di Employee prima si imposta il prototipo, in modo tale che l'oggetto non abbia ereditato i nuovi valori del prototipo.

Successivamente, qualsiasi oggetto creato dopo aver impostato il prototipo erediterà il nuovo oggetto prototipo.

Infine, l'oggetto avrà la proprietà isWorking anziché una proprietà working.

Quindi, per rifare il tuo esempio:

function Employee(name) { this.name= name; }; 

var m1 = new Employee("Bob"); 

var working= { isWorking: true }; 
Employee.prototype = working; 

var m2 = new Employee("Sam"); 

alert(m1.isWorking); // undefined 
alert(m2.isWorking); // true 
2

La modifica del prototipo non influisce su un oggetto già creato. Influirà solo sugli oggetti creati in base a quell'oggetto.

C'è una proprietà __proto__ che può essere utilizzata per modificare il prototipo, ma la sua implementazione non è richiesta. ES6 definisce il metodo setPrototypeOf per modificare il prototipo, ma poiché è solo in ES6, il supporto può variare.

1

La soluzione semplice è assegnarlo correttamente.

function Employee(name) { 
    this.name = name; 
} 
var m = new Employee("Bob"); 
var working = { 
    isWorking: true 
}; 
Employee.prototype.working = working; 
alert(m.working.isWorking); 

Una migliore soluzione per i dipendenti multipla è di fare una classe, quindi creare le istanze di quel: giocare con qui: http://jsfiddle.net/MarkSchultheiss/p6jyqbgv/1/

"use strict"; 
function makeClassStrict() { 
    var isInternal, instance; 
    var constructor = function(args) { 
    if (this instanceof constructor) { 
     if (typeof this.init == "function") { 
     this.init.apply(this, isInternal ? args : arguments); 
     } 
    } else { 
     isInternal = true; 
     instance = new constructor(arguments); 
     isInternal = false; 
     return instance; 
    } 
    }; 
    return constructor; 
} 
var EmployeeClass = makeClassStrict(); 
EmployeeClass.prototype.init = function(employeeName, isWorking) { 
    var defaultName = 'notbob'; 
    this.name = employeeName ? employeeName : defaultName; 
    this.working = !!isWorking; 
}; 
// call this to get the name property 
EmployeeClass.prototype.getName = function() { 
    return this.name 
}; 
//note no "new" needed due to the makeClassStrict that does that 
var m = EmployeeClass("Bob"); 
alert(m.working +":"+ m.name); 
m.working = true; 
alert(m.working +":"+ m.name); 
var notbob = EmployeeClass("Charlie",false); 
alert(notbob.working +":"+ notbob.name); 
alert(notbob.getName()+ m.getName()); 
1

Non è possibile sostituire l'intera proprietà del prototipo e si aspettano già le istanze di lavoro esistenti. JavaScript non funziona in questo modo. Ma puoi scorrere l'oggetto prototipo e rimuovere tutto ciò che è già impostato, quindi eseguire il loop del tuo nuovo oggetto e impostarlo su qualcos'altro.

function Employee(name) { this.name= name; } 
var m = new Employee("Bob"); 
var working= { isWorking: true }; 
for(var j in Employee.prototype){delete Employee.prototype[j];}//unset all properties, the same as setting to {} 
for(j in working){Employee.prototype[j]=working[j];}//set the properties 
alert(m.isWorking); 
+0

Non è possibile eseguire questa operazione, poiché gli attributi dichiarati esplicitamente del prototipo non possono essere eliminati in modo obsivo utilizzando la parola chiave 'delete'. –

+0

@ Æðelstan Guardate voi stessi: http://jsfiddle.net/L2yvjtow/ – Ultimater

+0

Funziona, buon punto! –

Problemi correlati