2015-12-08 15 views
5

Więc uczę prototyp przy użyciu javascript i spróbował jakiś kod:niezdefiniowany wynik za pomocą prototypowego [JavaScript]

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

Niestety, mam niezdefiniowanej wiadomość, zamiast prawdziwej wartości. Czy istnieje powód do tego wyniku?

Wykonałem kilka testów. Doszedłem do wniosku, że ponowne przypisanie obiektu prototypowego powoduje, że wszystkie utworzone wcześniej instancje klasy Employee nie mogą uzyskać dostępu do żadnych właściwości znalezionych w nowo przypisanym prototypie. Czy to jest dokładne?

+3

Podczas tworzenia instancji odwołuje się do prototypu konstruktora w danym momencie. Jeśli później zastąpisz prototyp, istniejące instancje tego nie odzwierciedlą. Po utworzeniu instancji zazwyczaj oczekuje się rozszerzenia prototypu zamiast jego zastępowania. –

+5

Odwołanie do instancji obiektu prototypowego jest ustawione na czas budowy (tj. Wiersz z 'nowym'). Zmiana całego obiektu właściwości 'Foo.prototype' nie zmieni tego odniesienia na instancji po. Jednak zmiany w obiekcie 'Foo.prototype' będą widoczne (ponieważ jest to ten sam obiekt), np. jeśli zamiast tego zrobiłeś 'Employee.prototype.isWorking = true;', zobaczyłbyś, czego się spodziewasz –

+0

W celu dalszego czytania, jest to naprawdę dobry upadek prototypowego dziedziczenia: http://markdalgleish.com/2012/10/a -touch-of-class-inheritance-in-javascript/ – br3nt

Odpowiedz

1

Po pierwsze, po utworzeniu instancji Employee przed ustawiasz prototyp, aby obiekt nie odziedziczył nowych wartości prototypu.

Następnie dowolne obiekty utworzone po ustawieniu prototypu odziedziczą nowy obiekt prototypu.

Na koniec obiekt będzie miał właściwość isWorking, a nie właściwość working.

więc przerobić swój przykład:

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

Zmiana prototypu nie wpłynie na już utworzony obiekt. Dotyczy to tylko obiektów utworzonych na podstawie tego obiektu.

Istnieje właściwość __proto__, której można użyć do zmiany prototypu, ale jej implementacja nie jest wymagana. ES6 definiuje metodę setPrototypeOf, aby zmienić prototyp, ale ponieważ jest to tylko w ES6, wsparcie może się różnić.

1

Prostą poprawką jest prawidłowe przyporządkowanie.

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

Lepszym fix dla wielu pracowników jest, aby klasy, a następnie utworzyć instancji, że: bawić się z nim tutaj: 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

Nie można zastąpić całą własność prototypu i oczekują już istniejących instancji do pracy. JavaScript nie działa w ten sposób. Możesz jednak przechodzić przez obiekt prototypu i anulować wszystko, co już zostało ustawione, a następnie przepętlić nowy obiekt i ustawić go na coś innego.

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

Tak naprawdę nie można tego zrobić, ponieważ nie można usunąć jawnie zadeklarowanych atrybutów prototypu za pomocą słowa kluczowego "delete". –

+0

@ Æðelstan Zobacz sam: http://jsfiddle.net/L2yvjtow/ – Ultimater

+0

To działa, dobry punkt! –

Powiązane problemy