JavaScript:从原型继承的属性究竟如何

javascript: how exactly are properties inherited from prototype?

本文关键字:属性 究竟 继承 原型 JavaScript      更新时间:2023-09-26

考虑一段代码

function F(){
   this.p=10;
}
F.prototype.newProp='some value';
var f1=new F(), f2=new F();
alert(f1.__proto__==f2.__proto__); //returns true. implies f1 and f2 share same instance of prototype object 
f1.newProp='new value'; //changing the value of inherited property
alert(f2.newProp); //returns 'some value' 

好的,现在的问题是 f1 和 f2 是否共享相同的 [[prototype]] 对象实例如果JavaScript中的属性检索通过沿着原型链行走来工作

因此,如果我更改共享 [[prototype]] 对象的属性(在本例中为 newProp)的值,为什么它没有反映在F2中,自F1以来。原型==F2。proto(这意味着它是相同的对象)那么为什么更改 f1 的 newProp 不会更改 f2 的 newProp(两者都继承自同一个原型对象,不是吗?

令人惊讶的是,改变 f1。proto.newProp 反映了检索"f1.newProp"时的更改

所以,f1.newProp和f1也是如此。proto.newProp 不同的属性 ?

我认为在 javascript 中查找属性是通过在原型链中依次查找更高的属性来工作的。

如果我的问题听起来很幼稚,我很抱歉,但我无法理解:

如果 1) f1。原型==F2。原型//真!暗示对象 F1 和 F2 引用它们继承的相同 [[原型]] 对象

如果

2)在对象中找不到的属性在其原型中搜索。

那么为什么更改 f1.newProp 也不会反映在 f2.newProp 中呢? 因为两者都具有共同的[[原型]]属性,如第(1)点所示

是原型对象的属性被单独复制到 f1 和 f2 中吗?但这违反了第 (2) 点 [在对象中找不到时查找原型链的属性]

请解释一下这里的矛盾。非常感谢:)

=================编辑

==

==================

谢谢@jfriend00的回复。

但假设我有这段代码

function Person(name, age){      
    this.name=name;
    this.age=age;
    alert("obj created:"+name);
}
function Employee(name,age,eid){
    this.base=Person;
    this.base(name,age);
    this.eid=eid;
}
Employee.prototype=new Person;
var ob1=new Employee('name1',23,100);
var ob2=new Employee('name2',24,101);

在这里,显然也是 ob1。原型==ob2。原始但是如果我没记错的话,每个员工实例都有 2 个对象

1

是员工对象本身,只有 1 个属性 EID(和其他一个基本函数)

第二个是 Person 对象,它由员工对象的 [[原型]] 属性引用。此对象具有名称和年龄属性。因此,员工 obj 实际上存储并从其 [[原型]] Person 对象中检索姓名和年龄。我说的对吗?

如果是这样,并且由于 ob1。原型==ob2。proto,那么我们如何能够存储两个对象的唯一名称和年龄?

我的意思是,这里似乎每个员工都有一个原型对象。如果你能解释一下,非常感谢:)

另一个查询是:

为什么即使注释掉

Employee.prototype=new Person;

在上面的行中,从而断开了 2 个 OBJ 之间的链接。继承仍然有效,因为我已将 Person 函数声明为员工的属性并从中调用 Person。这是如何工作的谢谢:)

一旦你设置了f1.newProp = 'new value',它就不再设置newProp原型,而是设置在f1对象本身上。试试这个,你会看到:

var f1=new F(), f2=new F();
console.log(f1.hasOwnProperty('newProp')); // returns false, because it is from prototype
f1.newProp = 'new value';
console.log(f1.hasOwnProperty('newProp')); // returns true

原型对象在所有对象之间共享(如您所所示)。

但是,当您为属性分配对象时,它不会更改原型,属性位于对象本身上,

并且由于解析属性引用的查找顺序,对象本身上新分配的属性在原型上的属性之前找到,因此它成为活动属性。

在对象上引用属性时,存在搜索顺序。 首先,它直接在对象上查找属性。 如果未找到匹配项,则搜索原型链。

当您写入对象

上的属性时,除非您显式引用原型对象,否则它永远不会写入原型,而是直接将属性放在对象上,然后该属性成为活动属性(实质上覆盖原型上的内容)。

您可以使用 .hasOwnProperty() 判断属性是在对象本身上还是在原型上。 仅当属性直接位于对象上时,才会返回true

因此,在您的代码中:

f1.newProp='new value'; //changing the value of inherited property

这会将新属性直接添加到对象(而不是在原型上),并且它实质上覆盖了原型上的内容。


通常,数据属性通常在构造函数中设置,以避免对属性可以驻留的两个可能位置产生任何混淆,并且,如果要写入它们,则最初在原型上指定它们实际上没有任何优势。 函数属性(例如方法)通常在原型中设置,因为它们通常不会被写入,因此只有一个共享原型对象,其中包含可以从中读取的它们,效率更高。