【问题标题】:Prototypes and object creation原型和对象创建
【发布时间】:2011-09-28 16:02:40
【问题描述】:

最近我试图了解原型链的技术方面。现在我有几个关于对象实例化的问题。

考虑以下代码:

var Foo = function(s) {
  this._bar = s;
};

var fooInst = new Foo('test');

现在当我检查创建的对象时,然后:

Foo.prototype === Function.prototype; // true

fooInst.prototype === ?
fooInst.prototype.prototype === Object.prototype; // true

我想知道,fooInst.prototype 到底是什么。在 Chromes 检查器中,它似乎是某种带有constructor 属性的Foo。但我读到的所有关于原型的资料都表明fooInst.prototype === Foo.prototype 应该是真的。

所以我的问题是:JS 究竟是如何处理原型链的。当我打电话给new Foo 时会发生什么。

提前致谢!

编辑

所以我发现(在 Chrome 中)Object.getPrototypeOf(fooInst) === Foo.prototype;true,但 Object.getPrototypeOf(fooInst) === Object.getPrototypeOf(Foo)false。为什么会这样?

【问题讨论】:

  • Foo 是一个函数,fooInst 是一个Foo

标签: javascript inheritance object prototype-programming


【解决方案1】:

我想知道 fooInst.prototype 到底是什么。

它是undefined

fooInst.prototype === undefined; // true

只有函数具有自动 .prototype 属性。对象没有。

如果您使用构造函数创建对象,例如:

var fooInst = new Foo('test');

...那么fooInst 将有一个对Foo.prototype 的内部引用,但是没有标准 属性可以从fooInst 获取Foo.prototype


也就是说,一些 JavaScript 环境支持一个非标准属性来引用原型对象。

fooInst.__proto__ === Foo.prototype; // true (if __proto__ supported)

另外,还有一个ECMAScript 5提供的方法可以使用。

Object.getPrototypeOf( fooInst ) === Foo.prototype;  // true

从对象到其原型对象的内部引用可能只是此类引用链中的第一个。

原型对象可能有它自己的原型对象被引用。 (在基本情况下,这将是 Object.prototype,或者对于更长的链,Object.prototype 可能在链的更下游。)

Object.prototype 本身引用null 作为其原型。这结束了链条。

您应该注意,如果您更改构造函数的.prototype 对象,则从对象到其原型对象的内部引用不会改变。它是对象生命周期中存在的引用。

var Foo = function(s) {
  this._bar = s;
};

var fooInst = new Foo('test');

Object.getPrototypeOf( fooInst ) === Foo.prototype;  // true

// Change the prototype object of Foo
Foo.prototype = { some:'object' };

Object.getPrototypeOf( fooInst ) === Foo.prototype;  // false

【讨论】:

  • 但我假设,任何对象都有原型对象?而Object.getPrototypeOf(fooInst) 给了Foo.prototype
  • @mAu:是的,看我的更新。我引用了标准的.getPrototypeOf() 方法和非标准的.__proto__ 属性。如果使用Object.create() 创建对象,实际上可以将原型设置为null 而不是Object。 var o = Object.create( null );
  • 感谢您的澄清!
【解决方案2】:

你的第一个假设:

Foo.prototype === Function.prototype;

不对,我认为你混淆了所有对象都具有的[[Prototype]]内部属性的概念,并且使原型链的“链接”和函数对象具有的prototype属性。

上述比较将产生false,因为Foo.prototype 属性的值是一个新对象,在您创建Foo 函数时创建。

这个对象在你创建一个函数对象时被初始化,它继承自Object.prototype并且它有一个名为constructor的属性指向函数(Foo.prototype.constructor === Foo),当你调用你的函数时使用它作为构造函数。

现在,如果我们谈论[[Prototype]] 内部属性,你是对的,你的Foo 函数的[[Prototype]]Function.prototype,换句话说,Foo 继承自Function.prototype,例如:

Object.getPrototypeOf(Foo) === Function.prototype; // true
Foo instanceof Function; // true
Foo.__proto__ === Function.prototype; // true

关于fooInst这个对象是在一个新表达式中创建的,当你使用你的Foo函数作为构造函数时,这个新对象就会产生,它继承自Foo.prototype,(它的内部[[Prototype]] 属性指向Foo.prototype)。

它没有prototype 属性,因为这个属性只对函数对象有意义。

另见:

【讨论】:

  • 也谢谢你,你说得对,我把prototype[[Prototype]]s这两个混淆了。
【解决方案3】:

您可能会在这里找到有用的JavaScript. The Core 中的解释和图表。

所有对象都有一个原型链。因此,fooInst 有一个原型链,其头部是Foo.prototype。当您调用new Foo 时,会创建一个Object,将Foo.prototype 设置为其原型链,并在新Object 的上下文中调用构造函数。

一些浏览器将此作为非标准 __proto__ 属性公开,例如:

fooInst.__proto__ === Foo.prototype

【讨论】:

  • 感谢链接,非常有用!
猜你喜欢
  • 2014-11-26
  • 1970-01-01
  • 1970-01-01
  • 2013-10-15
  • 1970-01-01
  • 2012-07-27
  • 1970-01-01
  • 1970-01-01
  • 2018-01-28
相关资源
最近更新 更多