原型链 - 在这种情况下是使用原型链吗?
我跟着凯尔辛普森的YouDontKnowJS关于frontendmasters.com,并且被他的一个例子弄糊涂了。原型链 - 在这种情况下是使用原型链吗?
下面是示例代码:
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
警报函数被调用,this.identify()也被称为。 - 当调用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()方法创建一个具有指定原型对象的新对象和属性
当我们调用
Bar.prototype = Object.create(Foo.prototype)
,不应Bar.prototype
现在引用新的对象,是Foo.prototype
副本...
Object.create
不复制对象。它创建了一个新的对象,其原型underyling是我们传递所以用这个首发:
+---------------+ | 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__
属性。]
“当我们调用Bar.prototype = Object.create(Foo.prototype),不应该Bar.prototype现在引用一个新的对象,它是Foo.prototype的副本。“
Object.create不会创建对象的副本,但会为该对象创建委派。所以你必须上升一级到Foo.prototype
,因为这就是Bar.prototype
所委托的。
嗯。我对此有点困惑。如果它为该对象创建了一个委派,并且添加了上面代码中的'speak'属性。为什么不是Foo.prototype也包含发言属性?为什么文档说它创建了一个新对象?我不问,我只是没有看到这是如何工作的? – HelloWorld 2014-09-28 16:59:12
这很有道理,谢谢!只是为了澄清我最后一个问题。在该Bar.prototype上,它有__proto__,它是Prototype链接的公共版本,那么它也会有说法? – HelloWorld 2014-09-28 17:04:28
@HelloWorld:是的,稍后,我们添加它。不是在Object.create之后。我应该证明这一点。 – 2014-09-28 17:06:49
很好的解释,非常感谢@ T.J Crowder! – HelloWorld 2014-09-28 17:08:02