一尘不染

如何检测一个函数是否被称为构造函数?

javascript

给定一个功能:

function x(arg) { return 30; }

您可以用两种方式来称呼它:

result = x(4);
result = new x(4);

第一个返回30,第二个返回一个对象。

您如何检测 在函数本身内部 调用 该函数的方式

无论您采用哪种解决方案,它都必须与以下调用一起使用:

var Z = new x(); 
Z.lolol = x; 
Z.lolol();

当前所有解决方案都认为将该Z.lolol()方法称为构造函数。


阅读 675

收藏
2020-05-01

共1个答案

一尘不染

我认为[ES2015之前]您想要的东西是不可能的。函数内根本没有足够的信息来进行可靠的推断。

查看ECMAScript 3rd Edition规范,new x()调用时所采取的步骤实质上是:

  • 创建一个新对象
  • 将其内部的[[Prototype]]属性分配给的prototype属性 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可以覆盖每个由此构造的对象的多余的属性,但是我认为这是您可以做的最好的事情。

(*) “ instance of”是一个不准确的术语,但足够接近,并且比“ x作为构造函数调用而创建的对象”更为简洁

2020-05-01