【问题标题】:Is a constructor always a function object?构造函数总是函数对象吗?
【发布时间】:2012-05-01 05:15:50
【问题描述】:

我正在阅读最新的 ECMA-262 参考资料,2011 年 6 月 5.1 版。

8.6.2 表 9 部分中,我们有关于 [[Construct]] 内部属性的内容:

创建一个对象。通过 new 运算符调用。这 SpecOp 的参数是传递给 新运营商。实现此内部方法的对象 被称为构造函数。

标准并没有说构造函数必须是函数对象。那么我们可以有一个不是函数对象的构造函数对象吗?

Link to the standard as requested

【问题讨论】:

  • 您能链接到规范文档吗?如果没有您提供的报价的更完整上下文,我认为没有多少人能够回答。 (不过有趣的问题!)
  • 您可能对Annotated ES5 感兴趣,它是ECMA-262 5.1 标准PDF 的HTML 转换。它具有部分锚点,例如 Section 8.6.2 的锚点。
  • 如果我没记错的话,Crockford 说过,一般来说,在 JS 中使用构造函数并不是一个好的模式
  • 实际上正在阅读规格......太棒了。
  • @Thepoosh Crockford 还声称 ++ 运算符在 JS 中不是一个好的模式......

标签: javascript


【解决方案1】:

答案非常简单。 ES5 § 4.3.4 说:

Constructor Function object that creates and initialises objects.

所以你有它,根据定义,只有一个 Function 可以是一个构造函数。但是,可能有一些宿主对象的行为类似于构造函数,它们不具有本机 Function 对象的任何其他属性(例如,在 ActiveX 中实现的 IE 中的原始 XMLHttpRequest 对象)。

【讨论】:

  • 我接受这个作为答案。恕我直言,规范并不完全清楚,因为似乎不是函数的对象仍然可以具有 [[Construct]] 内部属性,至少问题中引用的表 9 没有明确禁止这一点。如果有人知道该规范的作者是谁,我想给他写一封电子邮件并要求澄清。
【解决方案2】:

虽然定义了术语“构造函数”(如@RobG pointed out),但没有什么可以阻止非“构造函数”对象拥有[[Construct]] 方法。

这有点令人困惑。这意味着您可以在不是Function 的对象上使用new 运算符(因此不是4.3.4 中的“构造函数” ),但确实提供了[[Construct]] 方法。

请注意,没有任何标准对象符合此条件,但 host objects 确实可能。像 Java 这样的浏览器插件可能会暴露一些对象,如下所示:

new java.lang.String(); // it works, so java.lang.String has a [[Construct]] method
java.lang.String instanceof Function // false
Object.prototype.toString.call(java.lang.String).indexOf('Function') // -1

请注意,typeof java.lang.String 返回 "function",即使 java.lang.String 不是函数。根据11.4.3,这是正确的(它是带有[[Call]] 方法的主机对象)

【讨论】:

  • 接下来你会迷失在“什么是函数?”的语义中。该规范仅涵盖本机对象(包括内置对象)并明确允许宿主对象做他们喜欢的事情。主机对象的创建者遵循 ECMA-262 是有道理的,但是在很多情况下他们没有遵循,很高兴看到一个不是 IE 的示例。 :-)
  • @RobG 不确定你在这里想说什么。 8.6.2 在一定程度上涵盖了宿主对象。此外,术语“功能”在4.3.24 中定义
  • @RobG 我认为问题在于规范并不完全一致。
  • @Pumbaa80——你引用的部分说Host objects **may** support these internal properties with **any implementation-dependent behaviour**...,并且对这种行为几乎没有限制。此外,还有许多可调用的宿主对象不符合 ECMAScript 的函数概念(例如,它们不是 Function 的实例)。
  • 好的。这确实有点令人困惑。我认为规范的作者非常了解当前的实现,并为这些实现做出了准确的定义,故意允许奇怪的组合,比如“不是函数的可调用宿主对象”。
【解决方案3】:

添加到 Pumbaa80 的 answer(评论太长了)。

13.2.2 增加了混乱,据此,当一个 函数的 construct 被执行时,它的call 操作必须被执行(但它没有说明必须做什么)当执行不是函数的对象的construct 时)。现在,根据9.11,实现call 的对象是可调用的函数 对象。

还根据4.2“函数是可调用对象”。但这当然并不意味着每个可调用对象都是一个函数。

所以如果我做对了,非 Function 对象可以有一个 Construct 方法和一个 Call 方法。 java.lang.String 就是这样一个例子。

【讨论】:

    猜你喜欢
    • 2022-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-20
    • 2021-10-22
    • 2017-06-03
    • 1970-01-01
    相关资源
    最近更新 更多