67

我对 JavaScript 原型概念的概念相当陌生。

考虑以下代码:

var x = function func(){
}

x.prototype.log = function() {
  console.log("1");
}

var b = new x();

据我了解,b.log()应该返回 1 因为x是它的原型。但是为什么属性b.prototype未定义?

b.prototype应该返回对x函数的引用吗?

4

5 回答 5

77

只有构造函数有原型。既然x是构造函数,x就有原型。

b不是构造函数。因此,它没有原型。

如果您想获得对构造函数的引用b(在本例中为x),您可以使用

b.constructor
于 2013-01-22T02:47:22.290 回答
24

.prototype当函数作为构造函数被调用时,函数的属性只是为了在新对象上设置继承。

创建新对象时,它会将其内部[[Prototype]]属性设置为函数.prototype属性指向的对象。

对象本身没有.prototype属性。它与对象的关系完全是内部的。

这就是它起作用的原因b.log()。当 JS 引擎看到b对象本身没有log属性时,它会尝试在 objects 内部[[Prototype]]对象上查找它,并成功找到它。

需要明确的是,该[[Prototype]]属性不可直接访问。它是一个内部属性,只能通过 JS 引擎提供的其他构造间接可变。

于 2013-01-22T02:49:12.833 回答
15

JavaScript 中的所有普通对象都有一个内部原型槽(注意:这里的原型不是指原型属性)。ECMAScript 标准 ( http://www.ecma-international.org/ecma-262/6.0/index.html ) 指定此插槽称为 [[Prototype]]。您可以通过 __proto__ 属性访问此插槽。

__proto__ 可能无法跨浏览器可靠地使用。__proto__ 成为 ECMAScript 6 中的官方属性

然而,原型属性是构造函数上的一个属性,它设置构造对象上的 __proto__ 属性。

您可以访问某些类型的原型属性,例如核心 JavaScript 类型(日期、数组等)。还有一个 JavaScript 函数(可以看作是一个构造函数)有一个公共的原型属性。但是,函数的实例没有原型属性。

在你的情况下var b = new x();,b 是函数 x 的一个实例。因此 b.prototype 是未定义的。但是,b 确实有一个内部 [[Prototype]] 插槽。如果您b.__proto__在 Google Chrome 中输出,例如版本 63.0.3239.132,或在 Firefox 中输出,例如版本 43.0.4

console.log(b.__proto__);

您将看到它的 [[Prototype]] 插槽,如下所示:

{log: ƒ, constructor: ƒ}

而已。


仅供参考,整个代码片段如下:

var x = function() {
};
x.prototype.log = function() {
  console.log("1");
}

var b = new x();
b.log();  // 1

console.log(b.prototype); // undefined
console.log(b.__proto__); // {log: ƒ, constructor: ƒ}
console.log(x.prototype); // {log: ƒ, constructor: ƒ}
于 2016-02-08T23:57:00.913 回答
14

在浏览您的代码之前,我想确保了解您的代码行为所需的原型概念。

  1. [[prototype]]是 JavaScript 对象的隐藏属性。这个隐藏属性只不过是一个链接Object.prototype(如果由对象字面量创建)。没有标准方法可以访问此[[prototype]]属性。
  2. JavaScript中的函数是对象,所以它们也有[[prototype]]属性。在这里,如果是函数,这个隐藏的属性是一个链接Function.prototype。也没有标准的方法来访问这个[[prototype]]属性。
  3. 除了这个隐藏链接之外[[prototype]],每当创建一个函数对象时,都会在其中创建一个prototype属性,该属性与隐藏属性是分开的[[prototype]]

现在来到你的代码:

var x = 函数 func(){}

执行此行时,将x创建一个带有两个链接的函数对象:

  • Function.prototype(不可访问),
  • x.prototype(可访问)。

x.prototype.log = function() { console.log("1"); }

正如我们现在知道的那样,它x是一个函数对象,因此x.prototype可以访问,因此您可以在此处包含 log 方法。

var b = 新 x();

b是一个对象,但不是函数对象。它有那个隐藏的链接[[prototype]],但它是不可访问的。因此,当您尝试访问时,b.prototype它会给出undefined结果。如果您想检查原型,b则可以看到(x.prototype).isPrototypeOf(b);它将返回true。所以你可以说隐藏链接被引用x.prototype

以下是有关原型的一些事实:

  1. 如果对象O是用O = new func(){}然后 O[[prototype]] 创建的Function.prototype
  2. 如果对象O是用O = {}然后 O[[prototype]] 创建的Object.prototype
  3. 如果对象O是用O = Object.create(obj)然后 O[[prototype]] 创建的obj
于 2014-09-15T15:21:41.297 回答
1

因为prototype是函数(实际上是构造函数)的属性,因为它定义了此类对象(从该原型所属的构造函数创建的对象)的属性/方法。看看这个链接

于 2013-01-22T02:46:33.380 回答