如何检测一个函数是否被称为构造函数? [英] How to detect if a function is called as constructor?

查看:258
本文介绍了如何检测一个函数是否被称为构造函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定一个函数:

function x(arg) { return 30; }

您可以通过两种方式进行调用:

You can call it two ways:

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

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

The first returns 30, the second returns an object.

如何检测函数在函数本身中被调用的方式?

How can you detect which way the function was called inside the function itself?

无论你的解决方案是什么,还有以下调用:

Whatever your solution is, it must work with the following invocation as well:

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

所有解决方案目前认为 Z.lolol()正在调用它作为构造函数。

All the solutions currently think the Z.lolol() is calling it as a constructor.

推荐答案

注意:现在可以在ES2015及更高版本。请参阅丹尼尔·韦纳的答案

NOTE: This is now possible in ES2015 and later. See Daniel Weiner's answer.

我'想想你想要的是可能的[在ES2015之前]。

I don't think what you want is possible [prior to ES2015]. There simply isn't enough information available within the function to make a reliable inference.

查看ECMAScript第三版规范,所采取的步骤, new x()本质上是:

Looking at the ECMAScript 3rd edition spec, the steps taken when new x() is called are essentially:


  • 创建一个新对象

  • 将其内部[[Prototype]]属性分配给 x
  • 的原型属性
  • 调用 x c>

  • 如果调用 x 返回一个对象,返回它,否则返回新对象

  • Create a new object
  • Assign its internal [[Prototype]] property to the prototype property of x
  • Call x as normal, passing it the new object as this
  • If the call to x returned an object, return it, otherwise return the new object

被调用可用于执行代码,所以唯一可以在 x 里测试的是 this 值,这是这里所有的答案都在做。正如你所看到的,当调用 x 作为构造函数时,一个新的* x 实例,当调用 x 时, x 的现有实例传递为 this 除非,因为它是由 x 创建的每个新对象分配一个属性:

Nothing useful about how the function was called is made available to the executing code, so the only thing it's possible to test inside x is the this value, which is what all the answers here are doing. As you've observed, a new instance of* x when calling x as a constructor is indistinguishable from a pre-existing instance of x passed as this when calling x as a function, unless you assign a property to every new object created by x as it is constructed:

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 构造的对象可以被覆盖,但我认为这是最好的。

Obviously this is not ideal, since you now have an extra useless property on every object constructed by x that could be overwritten, but I think it's the best you can do.

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

(*) "instance of" is an inaccurate term but is close enough, and more concise than "object that has been created by calling x as a constructor"

这篇关于如何检测一个函数是否被称为构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆