区分构造函数和普通函数

时间:2014-05-20 11:14:58

标签: javascript ecmascript-5

我想在不知道如何调用/实例化的情况下调用函数。根据我的理解,有两种方法可以使用new Foo()Foo()

因为我需要一个包装来调用这个函数,所以我们说它基本上是一个代理。我有一个函数的引用,但不知道我应该以哪种方式调用它,它应该是一个构造函数或一个普通的javascript函数。

由于似乎没有办法在两种方式之间产生分歧,我想出了以下内容。

var delegate;
var Foo = function() { };
    Foo.prototype.foo = function() { alert("foo") };

var bar = function(value) { alert(value); } 

function construct(constructor, args) {
    function F() {
        return constructor.apply(this, args);
    }
    F.prototype = constructor.prototype;
    return new F();
}

var proxy = function() { return construct(delegate, arguments) };

delegate = bar;
proxy("bar");

delegate = Foo;
new proxy().foo();

这给了我预期的结果,似乎有效。你觉得这个解决方案有什么不好吗?用new调用常规函数是不是很糟糕?这种技术的缺点是什么?

代码基于以下问题"Use of apply with the new operator"

1 个答案:

答案 0 :(得分:2)

  

是否可以区分构造函数和正常函数?

没有。每个普通(用户定义的)javascript函数都可以充当两者。在函数内部,您可能会根据this值的外观进行一些推理,但这不可靠。

另见How to detect if a function is called as constructor?

  

我有一个函数的引用,但不知道我应该以哪种方式调用它,它是指构造函数还是普通的javascript函数。

但是,您不需要知道 - proxy本身被知道它的人称为构造函数或普通函数。

  

你觉得我的解决方案有什么不好吗?

关于delegate的关闭,后来改变了,在开放时是丑陋的。在你的情况下,你似乎并不需要它,普通的proxy = bar;proxy = Foo;就足够了。此外,您的construct功能看起来不必要。

  

用new调用常规函数是不是很糟糕?这种技术的缺点是什么?

如果函数不使用this,则不会出现任何问题,但构造实例对象会产生开销。

对于在其他地方传递的代理函数(这样我们就不能轻易更改引用),我会使用delegate的显式setter:

function makeProxy(delegate) {
    function proxy() {
        return delegate.apply(this, constructor);
    }
    proxy.prototype = delegate.prototype;
    return {
        proxy: proxy,
        setTarget: function(d) {
            delegate = d;
            proxy.prototype = d.prototype;
        }
    };
}

var p = makeProxy(bar);
p.proxy("bar");

p.setTarget(Foo);
new (p.proxy)().foo();