JavaScript原型设计:单个原型对象与否?

时间:2010-08-26 03:57:35

标签: javascript oop subclass

我真的没有进行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中?

2 个答案:

答案 0 :(得分:1)

这是因为你写了

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

您正在创建一个实例 Class的原型。你想要的是创建一个继承其父类原型的子类。正如David Flanagan在他的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
}

(Crockford在所谓的ES5 object constructor property之后调用此函数Object.create,但请不要这样做can be misleading。)

在SubClass构造函数中,您必须callthis设置为当前对象的Class构造函数:

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

最后,但并非最不重要的是,您只需重置Class.asdf2一次,但不会重置ClassSubClass的构造函数。所以将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);

答案 1 :(得分: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的共享相同。