为什么在JavaScript中构造函数返回对象而不是原始值?

6

我尝试理解JavaScript(或至少是V8引擎)在构造函数方面的行为。

我知道,JavaScript构造函数永远不应返回任何内容(因此返回undefined)。

但考虑以下JavaScript代码:

function Thing() { 
  return '';
}
var t = new Thing();
console.log(t, typeof t); // => Thing {} "object"

现在,如果你这样做:
function Thing() { 
  return { hi: '' };
}
var t = new Thing();
console.log(t, typeof t); // => Object {hi: ""} "object"

甚至更多:

function Thing() { 
  this.a = 'a';
  return { hi: '' };
}
var t = new Thing();
console.log(t, typeof t); // => Object {hi: ""} "object"

那么,为什么JavaScript中的构造函数返回一个对象而不是原始值,如果你编写这种代码呢?
这种行为也在这个SO答案中提到,但没有解释。我还翻阅了ECMAScript规范的new Operator部分和它的Construct片段,但这并没有启示性。
有任何提示或知识吗(请用简单易懂的英语)?

2
首先,它并不是“错误和丑陋”的,因为它并没有做你认为它做的事情。而且,既然它不是原始对象,为什么要返回一个原始值呢? - Sterling Archer
3
简而言之,如果你从构造函数返回一个原始值,它将被忽略。如果你返回一个对象,它将被用作最终的对象。这回答了你的问题吗?或者你正在寻找这种行为的理由? - deceze
5
它表现出这种行为“是因为规范是这样规定的”。然而,我认为你正在寻找的“为什么”解释可能基于观点 - 你需要得到一个展示语言设计团队推理的答案,其他任何答案都只是某人的观点 - 例如,这是我的观点:你调用了new,所以你期望得到一个对象,也许语言设计团队觉得即使函数返回一个原始类型,你应该总是得到一个对象,但我没有什么确凿的理由来支持这个推理。 - James Thorpe
2
延续@James的推理...一个函数可能会返回像truefalse这样的副作用,可以安全地忽略;但如果返回一个“严肃”的对象,则应该将其作为对象构造函数的返回值。 - deceze
1
@jib 鸡和蛋的问题...你可以这样写,因为你可以这样写。如果你不能,你就不会这样写。 :) - deceze
显示剩余7条评论
1个回答

4

这是因为,按照定义,构造函数的目的是生成对象,而不是基本类型:

4.3.4 构造函数

创建和初始化对象的函数对象

因此,[[Construct]] 内部方法(通过 new 运算符 调用)会检查 [[Call]] 返回值的类型:

13.2.2 [[Construct]]

  1. result是调用F的[[Call]]内部属性的结果,并将obj作为this值,将传递到[[Construct]]的参数列表作为args提供。
  2. 如果Type(result)是对象,则返回result
  3. 返回obj

实际上,这是一个不变量:

[[Construct]] ( )

  • 返回值的类型必须是对象。

像你评论中的链接。我没有注意到。谢谢。在我看来,这并没有太多意义 - 但这不是发表观点的地方 :)。 - BairDev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接