【问题标题】:Is there no way to find the real constructor of an object in JavaScript有没有办法在 JavaScript 中找到对象的真正构造函数
【发布时间】:2015-10-07 17:01:55
【问题描述】:

我正在认真审查 ECMAScript 5.1 规范。

我很好奇是否有办法告诉 ES5 中对象的“真正的构造函数”是什么。 (不是显式的“构造函数”属性)

根据规范,显式“构造函数”属性只是从函数对象的副产品对象到函数对象的初始反向引用。

(这里,副产品是函数对象的显式“原型”属性最初指向的对象。)

因此,显式的“构造函数”属性与对象的真正构造函数无关:

function Foo(name){ this.name = name; }
var foo = new Foo("Brian");
var bar = { a: 10, b: function(){ if(this.name) return this.name; }};
Foo.prototype = bar;
var foo2 = new Foo("John");   // Let me call Foo as "real constructor" of foo2

这里,即使 foo2 是由 Foo 创建的,由于 Foo.prototype 在创建 foo2 的那一刻指向 bar,所以 foo2 的内部 [[Prototype]] 指向 bar,我们可以通过以下方式检查:

Object.getPrototypeOf(foo2) === bar   // true

由于 foo2 没有像往常一样拥有自己的“constructor”属性,所以,读取 foo2.constructor 实际上是 [[Prototype]] 链式查找,即 foo2.constructor --> (( foo2.[[Prototype] ] )).constructor --> bar.constructor 是 Object,而不是 Foo。

您可以通过以下方式检查:

foo2.constructor === Foo         // false
foo2.constructor === Object      // true

最后,有没有办法从对象 foo2 中找到 Foo?

添加: 我说的是 ES5。请不要带任何依赖引擎或 ES6 的东西(例如 __proto__

【问题讨论】:

  • 好吧,我要在这里冒险并说这是不可能的。据我所知,没有什么可以将构造函数与构造对象牢固地联系起来。您可以在创建对象后更改Foo.prototype,甚至foo2 instanceof Foo 将不再起作用。只需将构造函数视为蓝图。你用它来创建一个对象,但在你创建它之后,没有什么能阻止你对它们做完全不同的事情。
  • 另外,不要忘记构造函数完全有可能返回一个全新的对象而不是隐含的return this,在这种情况下绝对没有链接回到创建它的函数。

标签: javascript


【解决方案1】:

不,该语言本身不提供任何功能。

如果我们查阅spec on the new operator,我们会发现它主要是对函数的[[Construct]] 内部方法的调用。将注意力转向[[Construct]],我们看到:

当函数对象 F 的 [[Construct]] 内部方法使用可能为空的参数列表调用时,将执行以下步骤:

  1. obj 成为新创建的原生 ECMAScript 对象。
  2. obj的所有内部方法都按照8.12的规定设置。
  3. obj的[[Class]]内部属性设置为“Object”。
  4. 将 obj 的 [[Extensible]] 内部属性设置为 true
  5. proto 为使用参数“prototype”调用 F 的 [[Get]] 内部属性的值。
  6. 如果 Type(proto) 是 Object,则将 obj 的 [[Prototype]] 内部属性设置为 proto
  7. 如果 Type(proto) 不是 Object,则将 obj 的 [[Prototype]] 内部属性设置为标准内置 Object 原型对象,如 15.2 中所述.4.
  8. result 为调用 F 的 [[Call]] 内部属性的结果,提供 obj 作为 this 值并提供传入 [[构造]] 作为参数。
  9. 如果 Type(result) 是 Object 则返回结果。
  10. 返回obj

正如您在第 5 步到第 7 步中看到的,环境对new 创建的对象的唯一处理是设置其[[Prototype]],然后将其交给函数的[[Call]] 方法进行处理步骤 8. 如果分配给对象的[[Prtototype]] 的值不包含准确的constructor 属性,则无法知道是哪个构造函数创建了对象。

当然,您可以通过在创建时为对象设置一个值来将该信息存储在您自己的构造函数代码中,但 JavaScript 引擎不会为您执行此操作。

【讨论】:

  • 好的,现在看起来又清楚了。实际上,当 Chrome 控制台为上述示例正确吐出 真正的构造函数 时,我很好奇。因此,它必须是引擎的内部实现不公开。
猜你喜欢
  • 2015-10-11
  • 2014-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多