JavaScript 原型设计:是否单一原型对象?

发布于 2024-09-16 11:27:54 字数 975 浏览 5 评论 0原文

我不太了解 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]”?!如果原始原型对象(new Class(“proto_class”))被修改,那么为什么asdf变量不保持“changed_asdf”?如果不是,那么为什么 asdf2 数组包含“changed_asdf2”?此外,如何确保每个新的 SubClass() 实例都包含一个新的 Class() 实例,就像在 C++ 和 Java 中一样?

I don't really get JavaScript prototyping. Take this code, for instance:

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);

The first alert prints "proto_class []", as expected. The second alert prints "changed_asdf [changed_asdf2]", also as expected. But why does the third alert print "proto_class [changed_asdf2]"?! If the original prototype object (new Class("proto_class")) is being modified, then why doesn't the asdf variable remain "changed_asdf"? And if it isn't, then why does the asdf2 array contain "changed_asdf2"? Furthermore, how do I make sure that each new SubClass() instance contains a fresh instance of Class(), as in C++ and Java?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

猫腻 2024-09-23 11:27:54

这是因为您写道

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

您正在创建 Class一个实例的原型。您想要的是创建一个继承其父类原型的子类。正如 David Flanagan 在他的 JavaScript:权威指南 (§ 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调用这个函数Object.create,在所谓的ES5 对象构造函数属性,但请不要这样做,因为这个 可能会产生误导。)

在子类构造函数中,您必须使用 this类构造函数> 设置为当前对象:

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);

It's because you write

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

you are creating a prototype of one instance of Class. What you want is to create a sub-class that inherits from its parent's prototype. As David Flanagan shows in his JavaScript: The Definitive Guide (§ 9.5), you have to use a helper function to create a new object with a specified prototype:

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 calls this function Object.create, after the so-called ES5 object constructor property, but please don't do this, as this can be misleading.)

Within the SubClass constructor, you have to call the Class constructor with this set to the current object:

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

And last, but not least, you only reset Class.asdf2 once, but not in the constructor function of Class or SubClass. So add this.asdf2 = []; to one of the constructors.

The complete code now reads:

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);
谜泪 2024-09-23 11:27:54

这是因为 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 的共享相同。

This is because asdf2 is a mutable array on Class.prototype. That array is shared by all instances that delegate to that prototype. If you want each instance to have a separate asdf2, you have to assign it to this.asdf2 in some method.

Note that you assign this.asdf, but you never assign this.asdf2, you just push on to the existing array.

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.

The sharing of house in this example is the same as the sharing of asdf2 in the question.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文