2

快速说明:请不要在答案中解释 javascript 继承的基础知识。

这是一个简单的构造函数,它的原型成员附加了一些属性。

function Foo() { 
    this.relationship = "Love"; 
};

Foo.prototype.name = "Natalie";
Foo.prototype.age = 22;
Foo.prototype.country = "France";

现在我们用 Foo 创建新对象并测试一些基础知识。一切都很酷。

var girl = new Foo();

girl.hasOwnProperty("relationship"); //=> true
girl.hasOwnProperty("name");         //=> false

girl.relationship;  //=> "Love"
girl.name;          //=> "Natalie", this comes from Foo.prototype

girl.__proto__ === Foo.prototype;            //=> true
girl.__proto__.name === Foo.prototype.name;  //=> true
girl.name === Foo.prototype.name;            //=> true

如果我们更新 Foo.prototype.name 属性的值,girl.name 应该会指向新值。

Foo.prototype.name = "Lucia";
girl.name;  //=> "Lucia", this comes from Foo.prototype


当我们更改 Foo.prototype 并将其设为 null、未定义、空对象等时,会发生神秘的事情。

Foo.prototype = null;

如果我们的女孩对象有一个隐藏的__ proto__(ECMA [[Prototype]]) 链接到 Foo.prototype,那么在使 Foo.prototype为null之后,女孩应该没有机会获得name属性,但确实如此!

girl.name;     //=> "Lucia"
girl.age;      //=> 22
girl.country;  //=> "France"

现在,如果我们此时使用 Foo 创建另一个对象。它没有nameagecountry,因为当然 Foo.prototype 是空的。

var new_girl = new Foo();
new_girl.name;     //=> undefined
new_girl.age;      //=> undefined
new_girl.country;  //=> undefined


所以我的问题是,在我们将 Foo.prototype 分配给null之后,之前的对象(女孩)和他的隐藏链接如何记住这些属性?__ proto__

4

1 回答 1

2

一点都不神秘,也和传承无关。
它与对象指针/引用有关。

var a = { name : "Bob", age : 32 };
var b = a;

b.name; // "Bob";
a.name = "Jim";
b.name; // "Jim";
a = null;
b.name; // "Jim";

发生了什么?

ab获得指向同一个对象的指针。
当您更改object 的属性时a,通过引用一个或另一个(更改它们 on或 on都没有关系b),另一个引用也会看到更改。

您并没有创建具有相同属性和值的新对象,您只是给它们两个相同对象的地址,并且每次您询问它们时它们都会查找属性。

然后你重新分配a.

您没有更改对象,而是a将地址提供给其他地方。
b地址还是有的。

所以现在这样想:

function Foo () { }
Foo.prototype = { name : "Bob", age : 32 };

var a = new Foo();
var b = new Foo();

a.__proto__ === Foo.prototype;
b.__proto__ === Foo.prototype;

Foo.prototype.age = 35;

a.age; // 35
b.age; // 35

// now we're replacing the `.prototype` reference with a brand new object
Foo.prototype = { name : "Sally", age : 16 };

a.__proto__ !== Foo.prototype;
b.__proto__ !== Foo.prototype;

a.name; // "Bob"
b.age;  // 35

构造函数在后台所做的所有事情都是说:

this.constructor = arguments.callee;
this.__proto__   = this.constructor.prototype;

因此,当您更改两者引用的对象的属性时,对任一对象的this.constructor.prototype查找this.__proto__都会找到新值。
但是从一个中删除一个引用不会删除另一个的对象。

如果这是您想要的结果,那么您需要删除原型的每个属性(无论您从哪里执行它 - 从函数或任何实例),然后.prototype通过将其设置为空对象(null 会在较小的浏览器上导致错误),因此未来的对象无法访问。

于 2013-02-17T20:54:06.010 回答