__proto__为什么以及如何记住构造函数的旧属性's未定义的原型成员

Why and how __proto__ remembers old properties of the constructor function's undefined prototype member?

本文关键字:未定义 成员 原型 属性 何记住 proto 构造函数 为什么      更新时间:2023-09-26

快速提示:请不要在回答中解释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并使其为空、未定义、空对象等时,会发生一件神秘的事情。

Foo.prototype = null;

如果我们的girl对象有一个隐藏的指向Foo.Prototype的__ proto__(ECMA[[Prototype]])链接,那么在使Foo.Prototypenull之后,girl该没有机会获得name属性,但它确实有!

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

现在,如果我们在这一点上用Foo创建另一个对象。它没有名称年龄国家,因为Foo.prototype当然是null。

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


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

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

var a = { name : "Bob", age : 32 };
var b = a;
b.name; // "Bob";
a.name = "Jim";
b.name; // "Jim";
a = null;
b.name; // "Jim";

发生了什么?

3和CCD_ 4被赋予指向同一对象的指针
当您更改对象的属性时,通过引用其中一个或另一个(在ab上更改它们都无关紧要),另一个引用也会看到更改。

你不是在制作具有相同属性和值的新对象,你只是给它们同一个对象的地址,每次你问它们时,它们都在查找属性。

然后重新分配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.prototypethis.__proto__引用的对象的属性时,其中任何一个的查找都会找到新值
但是从一个引用中删除引用不会删除另一个引用的对象。

如果这是你想要的结果,那么你需要删除原型的每个属性(无论你从哪里做——从函数还是从任何实例),然后通过将.prototype设置为空对象来取消CCD_12(在较小的浏览器上为空会导致错误),这样未来的对象就无法访问。