我在frontendmasters.com跟随凯尔辛普森的YouDontKnowJS,并对他的一个例子感到困惑。
以下是示例代码:
function Foo(who){
this.me = who;
}
Foo.prototype.identify = function() {
return "I am " + this.me;
};
function Bar(who) {
Foo.call(this, who);
}
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.speak = function() {
alert("Hello, " + this.identify() + ".");
}
var b1 = new Bar("b1");
var b2 = new Bar("b2");
b1.speak();
b2.speak();
致电new Bar("b1")
时;当你调用b1.speak()时,他会引导你了解原型链发生的事情
Bar.prototype
调用alert函数时,也会调用this.identify()。this
对象(b1)上找不到它,所以它会查看它的原型。Bar.prototype
它找不到识别方法,因此它再次查找原型链。Foo.prototype
这是我不清楚的。当我们致电Bar.prototype = Object.create(Foo.prototype)
时,现在不应该Bar.prototype
引用一个新对象,该对象是Foo.prototype
的副本,其上会有identify()
方法吗?为什么要在原型链中又向Foo.prototype
添加一步才能找到identify()
方法?
来自文档的Object.create()
的官方定义:
Object.create()方法使用指定的原型对象和属性
创建一个新对象
答案 0 :(得分:4)
当我们致电
Bar.prototype = Object.create(Foo.prototype)
时,不应该Bar.prototype
引用一个新对象,该对象是Foo.prototype
的副本...
Object.create
没有复制对象。它创建了一个新对象,其底层原型是我们传入的。所以从这开始:
+---------------+ | Foo.prototype | +---------------+ +----------------------+ | [[Prototype]] |---->| Object.prototype | +---------------+ +----------------------+ | identify: ... | | [[Prototype]]: null | +---------------+ +----------------------+ | ... | +----------------------+
(为简单起见,我遗漏了identify
的函数对象。)
......当我们Bar.prototype = Object.create(Foo.prototype)
时,它会创建:
+---------------+ | Bar.prototype | +---------------+ +---------------+ | [[Prototype]] |---->| Foo.prototype | +---------------+ +---------------+ +----------------------+ | [[Prototype]] |---->| Object.prototype | +---------------+ +----------------------+ | identify: ... | | [[Prototype]]: null | +---------------+ +----------------------+ | ... | +----------------------+
稍后,执行Bar.prototype.speak = function...
行后,Bar.prototype
也会拥有speak
属性。
+---------------+ | Bar.prototype | +---------------+ +---------------+ | [[Prototype]] |---->| Foo.prototype | +---------------+ +---------------+ +----------------------+ | speak: ... | | [[Prototype]] |---->| Object.prototype | +---------------+ +---------------+ +----------------------+ | identify: ... | | [[Prototype]]: null | +---------------+ +----------------------+ | ... | +----------------------+
在var b1 = new Bar("b1");
之后,我们有:
+---------------+ | b1 | +---------------+ +---------------+ | [[Prototype]] |---->| Bar.prototype | +---------------+ +---------------+ +---------------+ | me: "b1" | | [[Prototype]] |---->| Foo.prototype | +---------------+ +---------------+ +---------------+ +----------------------+ | speak: ... | | [[Prototype]] |---->| Object.prototype | +---------------+ +---------------+ +----------------------+ | identify: ... | | [[Prototype]]: null | +---------------+ +----------------------+ | ... | +----------------------+
[在上文中,[[Prototype]]
指的是对象与其原型的内置链接;名称为[[Prototype]]
的对象上没有真正的属性。
实际上,在ES5中,没有办法从对象本身直接访问原型的链接,尽管ES5添加了Object.getPrototypeOf
,它允许您通过传入对象引用来检索它,例如, var p = Object.getPrototypeOf(someObject)
。 ES6将添加更多与对象原型交互的方式,包括Mozilla的JavaScript多年来拥有的__proto__
属性。]
答案 1 :(得分:1)
&#34;当我们调用Bar.prototype = Object.create(Foo.prototype)时,不应该Bar.prototype引用一个新对象,它是Foo.prototype的副本。&#34; < / p>
Object.create不会创建对象的副本,但会创建对该对象的委派。所以你必须再向上一级Foo.prototype
,因为那是Bar.prototype
所委托的。