javascript:属性是如何从原型继承的?

时间:2014-11-20 06:27:18

标签: javascript inheritance

考虑一段代码

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。 proto == f2。 proto (这意味着它的SAME对象) 那么为什么改变f1的newProp不会改变f2的newProp(都从相同的原型对象继承,没有?)

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

那么,是f1.newProp和f1。 proto .newProp不同的属性?

我认为该属性在javascript中查找,通过在原型链中连续看起来更高。

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

如果1)f1。 proto == f2。 proto // true!暗示对象f1和f2引用相同的[[prototype]]对象,它们从中继承

如果

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

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

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

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

================== EDIT =====

谢谢@ 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。 proto == ob2。 proto 但如果我没有弄错的话,每个员工的实例都有2个对象

1是员工对象本身,只有1个属性eid(和另一个基本功能)

2nd是Person对象,由employee对象的[[prototype]]属性引用。此对象具有名称和年龄属性.. 因此,员工obj实际上从其[[prototype]] Person对象存储和检索名称和年龄。 我是对的吗?

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

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

还有一个问题是:

即使注释掉

,上面的代码怎么会起作用
Employee.prototype=new Person;

在上面的行中,从而打破了2个objs之间的联系。继承仍然有效,因为我已将Person函数声明为Employee的属性并从中调用Person。 这是怎么回事 谢谢你:))

2 个答案:

答案 0 :(得分:1)

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

但是,当您为属性分配对象时,它不会更改原型,属性会继续对象本身,并且由于解析属性引用的查找顺序,新分配的属性对象本身在原型之前找到,因此它成为活动属性。

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

当您写入对象上的属性时,它永远不会写入原型,除非您显式引用原型对象,而是将属性直接放在对象上,然后该属性成为活动属性(基本上覆盖了什么&#39) ; s在原型上。)

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

所以,在你的代码中:

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

这会直接向对象添加一个新属性(而不是在原型上),它基本上会覆盖原型上的内容。


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

答案 1 :(得分:1)

设置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 。试试这个,你会看到:

{{1}}