2010-08-26 87 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在问题的共享。