我知道JavaScript中继承的概念是通过原型链,但我不确定我是否正确理解。当读取属性时,引擎将首先搜索实例自己的属性,如果未找到则将搜索实例的[[Prototype]]属性,该属性是对创建实例的函数原型的引用,搜索将继续进行,直到达到Object.prototype。对于以下代码:
var person1 = {
name: "Qiushi",
sayName: function() {
console.log(this.name);
}
};
person1.sayName(); // Qiushi
var person2 = Object.create(person1);
person2.name = "Alex";
console.log(person2.hasOwnProperty("sayName")); // false
person2.sayName(); // Alex
当person2继承自person1时,person2可以使用person1中定义的方法。但是 sayName 方法不是person1原型的属性,而是它只是它自己的属性。我的问题是,方法搜索是单独跟随原型链, person2 如何使用不在此链中的方法?
-------------------------------最终编辑-------------- -----------
如果您对此问题有同样的疑虑,请阅读我和Jimbo之间的对话。
答案 0 :(得分:6)
作为其他对象原型的对象并没有什么特别之处,它们只是对象。
当引擎转到读取属性时,首先它会查看对象本身以查看它是否具有它,如果有,则使用它。如果它没有,它会查看对象的原型,然后查看其原型等。
在您的代码中,person1
是person2
的原型,因此在sayName
上查找person2
时,由于引擎在person2
上找不到它{1}},它会查看person2
的原型person1
,并找到它。
这是您在代码中设置的简单的ASCII艺术图表:
+-------------------+ person1-----------------------+-->| (object) | | +-------------------+ | | __proto__ |-->(not shown, Object.prototype) | | name: "Qiushi" | | | sayName: function | | +-------------------+ | +--------------+ | person2---->| (object) | | +--------------+ | | __proto__ |--+ | name: "Alex" | +--------------+
这是一个更完整但尚未完全完整的版本:
+------------+ Object--->| (function) | +->(not shown, Function.prototype) +------------+ | | __proto__ |--+ +--------------------+ | prototype |---------------------------------+-->| (object) | +------------+ | +--------------------+ +-------------------+ | | __proto__: null | person1-----------------------+-->| (object) | | | toString: function | | +-------------------+ | | valueOf: function | | | __proto__ |--+ | ... | | | name: "Qiushi" | +--------------------+ | | sayName: function | | +-------------------+ | +--------------+ | person2---->| (object) | | +--------------+ | | __proto__ |--+ | name: "Alex" | +--------------+
答案 1 :(得分:1)
Object.create
返回一个新对象,其中提供的参数 是新对象的原型对象。
所以你现在得到了这个:
{person2} - name:'Alex' - {prototype} - name:'Quishi' - sayName:function
因此,如果您在person2上查找属性name
,它将在person2上找到该属性,而不是查看原型。如果您查找sayName
,它将无法在person2上找到它,因此它将查看原型并在那里找到它。
函数中引用的this
关键字取决于函数调用FROM的位置。这就是this
的工作原理。当您在对象上调用方法时,该对象将是该方法中的this
。因此,即使该方法在原型上,如果您调用this
,person2.sayName();
仍将引用person2。如果您要更改(例如通过.call
),您可以更改输出。
console.log(person2.name); // -> Alex person2.sayName(); // -> Alex person2.sayName.call(person2.__proto__); // -> Quishi, even though called on person2 person1.sayName(); // -> Quishi person1.sayName.call(person2); // -> Alex, even though called on person1
我指出这一点是因为在这个例子中误解this
的可能性与误解原型一样多。