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

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

问题描述

给定一个函数:

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 及更高版本中现在是可能的.请参阅丹尼尔·韦纳 (Daniel Weiner) 的回答.

我不认为你想要的是可能的 [在 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 3rd edition spec,调用new x()时的步骤基本上是:

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

  • 创建一个新对象
  • 将其内部的 [[Prototype]] 属性赋值给 x
  • 的原型属性
  • 正常调用x,将新对象作为this
  • 传递给它
  • 如果调用 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 的预先存在的实例无法区分as this 当将 x 作为函数调用时,除非你为 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.

(*) instance of"是一个不准确的术语,但足够接近,比通过调用 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天全站免登陆