如何使用动态数量的参数调用构造函数? [英] How to call a constructor with dynamic amount of arguments?

查看:119
本文介绍了如何使用动态数量的参数调用构造函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个构造函数,我不知道它需要的参数数量,例如:

I have a constructor and I don't know the number of arguments it needs, for instance:

function someCtor(a,b,c){
   var that = this;
   that.a = a;
   that.b = b;
   that.c = c;
}

我需要创建一个函数,该函数将返回该构造函数的实例动态数量的参数:

I need to create a function which will return the instance of that constructor with a dynamic amount of arguments:

function makeNew(ctor, arguments){
    // this doesn't work, but it shows what I'm trying to achieve
    return new ctor.apply(arguments);
}

我想使用该函数将动态参数传递给构造函数,如下所示:

I want to use the function to pass the dynamic arguments to the constructor like below:

var instanceOfCtor = makeNew(someCtor, [5,6,7]);

如何实现这个功能?

推荐答案

注意:请参阅最后的ES2015兼容性说明。

Note: See the ES2015 compatibility note at the end.

首先创建一个对象将其底层原型设置为对象构造函数上的 prototype 属性引用通过 Object.create ,然后调用构造函数通过函数#application

You do it by first creating an object setting its underlying prototype to the object the prototype property on the constructor refers to via Object.create, then calling the constructor via Function#apply:

function makeNew(ctor, arguments){
    var obj = Object.create(ctor.prototype);
    var rv = ctor.apply(obj, arguments);
    return rv && typeof rv === "object" ? rv : obj;
}

注意最后的一点点,所以我们正在模仿 new 运算符正确:当您通过 new 调用构造函数时,如果它返回非 null 对象引用,最终是 new 表达式的结果;如果它返回任何其他内容(或什么都没有),则由 new 创建的对象就是结果。所以我们模仿它。

Note the bit of fiddling at the end, so we're emulating the new operator correctly: When you call a constructor via new, if it returns a non-null object reference, that ends up being the result of the new expression; if it returns anything else (or nothing), the object created by new is the result. So we emulate that.

即使在ES5之前的浏览器上,你也可以模仿足够的 Object.create 来做那个:

Even on pre-ES5 browsers, you can emulate enough of Object.create to do that:

if (!Object.create) {
    Object.create = function(proto, props) {
        if (typeof props !== "undefined") {
            throw new Error("The second argument of Object.create cannot be shimmed.");
        }
        function ctor() { }
        ctor.prototype = proto;
        return new ctor;
    };
}






ES2015兼容性说明



如果您调用的构造函数是通过ES2015的 class 语法创建的,则上述操作无效,因为您可以这样称之为ES2015 class 构造函数。例如:


ES2015 Compatibility Note

If the constructor you're calling was created via ES2015's class syntax, the above won't work, because you can't call ES2015 class constructors that way. For example:

class Example {
    constructor(a, b) {
        this.a = a;
        this.b = b;
    }
}

const e = Object.create(Example.prototype);
Example.apply(e, [1, 2]); // TypeError: Class constructor Example cannot be invoked without 'new' (or similar)

好消息是只会在ES2015 +兼容的JavaScript引擎上发生,并且只有构造函数是通过 class 创建的;坏消息是它可能会发生。

The good news is that will only happen on an ES2015+-compatible JavaScript engine, and only if the constructor was created via class; the bad news is that it can happen.

那么如何让你的 makeNew 防弹?

事实证明这很容易,因为ES2015还添加了 Reflect.construct ,这正是你想要的 makeNew 要做但是以与 class 构造函数和函数构造函数。因此,您可以使用功能检测 Reflect.construct 并使用它(如果存在)(ES2015 JavaScript引擎,因此可能已使用类创建构造函数)并且如果它不存在则回退到上面(ES2015之前的引擎,将不会有任何构造函数):

It turns out this is quite easy, because ES2015 also added Reflect.construct, which does exactly what you want makeNew to do but does it in a way that's compatible with both class constructors and function constructors. So you can feature-detect Reflect.construct and use it if it's present (ES2015 JavaScript engine, so a constructor might have been created with class) and fall back to the above if it's not there (pre-ES2015 engine, there won't be any class constructors around):

var makeNew; // `var` because we have to avoid any ES2015+ syntax
if (typeof Reflect === "object" && Reflect && typeof Reflect.construct === "function") {
    // This is an ES2015-compatible JavaScript engine, use `Reflect.construct`
    makeNew = Reflect.construct;
} else {
    makeNew = function makeNew(ctor, arguments){
        var obj = Object.create(ctor.prototype);
        var rv = ctor.apply(obj, arguments);
        return rv && typeof rv === "object" ? rv : obj;
    };
}

这是纯ES5语法,所以在ES5引擎上运行,但使用的是ES2015的 Reflect.construct 如果它存在。

That's pure ES5 syntax, so runs on ES5 engines, but uses ES2015's Reflect.construct if it's present.

这篇关于如何使用动态数量的参数调用构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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