2010-08-26 48 views
1

我並沒有真正獲得JavaScript原型。以此代碼爲例:JavaScript原型:單個原型對象與否?

function Class(asdf) { 
if(typeof(asdf) == 'undefined') { 
} else { 
    this.asdf = asdf; 
} 
} 
Class.prototype.asdf = "default_asdf"; 
Class.prototype.asdf2 = []; 
Class.prototype.change_asdf = function() { 
this.asdf = "changed_asdf"; 
this.asdf2.push("changed_asdf2"); 
} 

function SubClass() { 
} 
SubClass.prototype = new Class("proto_class"); 
SubClass.prototype.constructor = SubClass; 

test1 = new SubClass(); 
alert("test1 asdf: " + test1.asdf + " " + test1.asdf2); 
test1.change_asdf(); 
alert("test1 asdf: " + test1.asdf + " " + test1.asdf2); 
test2 = new SubClass(); 
alert("test2 asdf: " + test2.asdf + " " + test2.asdf2); 

第一個警報按預期打印「proto_class []」。第二次警報打印「changed_asdf [changed_asdf2]」,也如預期。但爲什麼第三次提醒打印出「proto_class [changed_asdf2]」?!如果原始原型對象(新類(「proto_class」))正在被修改,那麼asdf變量爲什麼不保留「changed_asdf」?如果不是,那爲什麼asdf2數組包含「changed_asdf2」?此外,如何確保每個新的SubClass()實例都包含一個新的Class()實例,就像在C++和Java中一樣?

回答

1

這是因爲你寫

SubClass.prototype = new Class("proto_class"); 

要創建一個原型一個實例的Class的。你想要的是創建一個繼承父類原型的子類。正如David弗拉納根表示他JavaScript: The Definitive Guide(第  9.5),你必須使用一個輔助函數來創建新的對象與指定的原型:

function heir(p) { 
    function f(){}   // dummy constructor function 
    f.prototype = p;  // specify prototype object we want 
    return new f();  // create and return new object 
} 

(克羅克福德調用該函數Object.create,所謂ES5 object constructor property後,但請不要這樣做,因爲這can be misleading

在子類構造函數,你必須call類的構造函數與this設置爲當前對象:

function SubClass() { 
    // call the parent's constructor with 
    // `this` set to the current scope 
    Class.call(this, "proto_class"); 
} 

最後但並非最不重要的一次,您只重置Class.asdf2一次,但不在Class或​​的構造函數中。因此,將this.asdf2 = [];添加到其中一個構造函數中。

完整的代碼,原先爲:

function heir(p) { 
    function f(){}   // dummy constructor function 
    f.prototype = p;  // specify prototype object we want 
    return new f();  // create and return new object 
} 

function Class(asdf) { 
    if (typeof asdf != 'undefined') 
     this.asdf = asdf; 
} 

Class.prototype.asdf = "default_asdf"; 
Class.prototype.asdf2 = []; 
Class.prototype.change_asdf = function() { 
    this.asdf = "changed_asdf"; 
    this.asdf2.push("changed_asdf2"); 
} 

function SubClass() { 
    // call the parent's constructor with 
    // `this` set to the current scope 
    Class.call(this, "proto_class"); 
    this.asdf2 = []; 
} 

SubClass.prototype = heir(Class.prototype); 
SubClass.prototype.constructor = SubClass; 

test1 = new SubClass(); 
alert("test1 asdf: " + test1.asdf + " " + test1.asdf2); 
test1.change_asdf(); 
alert("test1 asdf: " + test1.asdf + " " + test1.asdf2); 
test2 = new SubClass(); 
alert("test2 asdf: " + test2.asdf + " " + test2.asdf2); 
0

這是因爲asdf2Class.prototype一個可變的數組。該陣列由委託給該原型的所有實例共享。如果您希望每個實例都有單獨的asdf2,則必須以某種方法將其分配給this.asdf2

請注意,您指定this.asdf,但您從未指定this.asdf2,您只需推入現有陣列即可。

var house = {nice: true}; 
var me = {home: house}; 
var roomie = {home: house}; 

// Now roomie has a party and trashes the place. 
roomie.home.nice = false; 

//and how's my house? 
me.home.nice === false; 
// because house is shared. 

house的本例中的共享相同的asdf2在問題的共享。