为什么 JavaScript 原型属性在新对象上未定义?

IT技术 javascript prototype
2021-03-10 19:22:51

我对 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函数的引用吗?

5个回答

只有构造函数有原型。因为x是构造函数,x有原型。

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

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

b.constructor
@VictorPiousbox 最精确、最详细的来源是ECMAScript 规范,但如果您不习惯阅读此类内容,则可能难以阅读。除此之外,我只会使用搜索引擎搜索信息。
2021-04-28 19:22:51
w3schools.com/js/js_object_prototypes.asp说“每个 JavaScript 对象都有一个原型。原型也是一个对象。” 你说的哪一个矛盾你的答案只有构造函数有原型
2021-05-05 19:22:51
彼得,你有什么关于所有 JS 对象模型的书籍/在线资源的推荐吗?
2021-05-10 19:22:51
看了这么多说每个对象都有原型的文章后,我认为即使是从函数(使用new)创建的对象也有一个!但现在我明白了。
2021-05-10 19:22:51

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

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

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

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

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

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

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

然而,prototype 属性是构造函数上的一个属性,它设置将成为构造对象上的 __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: ƒ}
@Atul,不确定您是否指的是 Object.prototype.constructor。构造函数属性返回对创建实例对象的 Object 构造函数的引用。您可以访问它,例如,var c = new x.prototype.constructor();var d = new b.__proto__.constructor();
2021-05-04 19:22:51
构造函数默认是隐藏属性。我对吗。
2021-05-19 19:22:51

在查看您的代码之前,我想确定一些理解您的代码行为所需的原型概念。

  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 = new 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.

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