注意:这在 ES2015 及更高版本中是可能的。看看丹尼尔·韦纳的回答。
我不认为你想要的(在ES2015之前)是可能的。函数中根本没有足够的信息来做出可靠的推断。
看看 ECMAScript 第 3 版规范,调用时采取的步骤基本上是:new x()
- 创建新对象
- 将其内部 [[原型]] 属性分配给
x
- 正常调用,将其作为新对象传递
x
this
- 如果调用返回一个对象,则返回它,否则返回新对象
x
关于函数的调用方式没有任何有用的信息可供执行代码使用,因此唯一可以在内部进行测试的是值,这就是这里的所有答案正在做的事情。正如您所观察到的,作为构造函数调用时* 的新实例与作为函数调用时传递的预先存在的实例没有区别,除非您将属性分配给构造时创建的每个新对象:x
this
x
x
x
this
x
x
function x(y) {
var isConstructor = false;
if (this instanceof x // <- You could use arguments.callee instead of x here,
// except in in EcmaScript 5 strict mode.
&& !this.__previouslyConstructedByX) {
isConstructor = true;
this.__previouslyConstructedByX = true;
}
alert(isConstructor);
}
显然,这并不理想,因为你现在在可以覆盖的每个对象上都有一个额外的无用属性,但我认为这是你能做的最好的事情。x
(*)“实例”是一个不准确的术语,但足够接近,并且比“通过调用构造函数而创建的对象”更简洁x