javascript中的动态对象构造? [英] dynamic object construction in javascript?

查看:136
本文介绍了javascript中的动态对象构造?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我想在javascript中使用从其他地方提供的参数调用函数时,我可以使用函数的 apply 方法:

When I want to call a function in javascript with arguments supplied from elsewhere I can use the apply method of the function like:

array = ["arg1", 5, "arg3"] 
...
someFunc.apply(null, array);

但是如果我需要以类似的方式调用构造函数呢?这似乎不起作用:

but what if I need to call a constructor in a similar fashion? This does not seem to work:

array = ["arg1", 5, "arg3"] 
...
someConstructor.apply({}, array);

至少不是因为我正在尝试:

at least not as I am attempting:

template = ['string1', string2, 'etc'];
var resultTpl = Ext.XTemplate.apply({}, template);

这不起作用:

Ext.XTemplate.prototype.constructor.apply({}, template);

任何可以使这个工作的方法? (在这个特殊情况下,我发现新的Ext.XTemplate(模板)会起作用,但我对一般情况感兴趣)

Any way to make that one work? (In this particular case I found that new Ext.XTemplate(template) will work, but I am interested in the general case)

类似的问题,但具体到内置类型,没有我可以使用的答案:
通过调用prototype.constructor.apply来实例化JavaScript对象

similar question but specific to built-in types and without an answer I can use: Instantiating a JavaScript object by calling prototype.constructor.apply

谢谢。

时间过去了,ES6和转换器现在已成为现实。
在ES6中,做我想做的事情是微不足道的: new someConstructor(... array)
Babel 会将其转换为ES5 new(Function.prototype.bind.apply( someConstructor,[null] .concat(array)))(); ,在如何构建JavaScript对象(使用'apply')?

Time has passed and ES6 and transpilers are now a thing. In ES6 it is trivial to do what I wanted: new someConstructor(...array). Babel will turn that into ES5 new (Function.prototype.bind.apply(someConstructor, [null].concat(array)))(); which is explained in How to construct JavaScript object (using 'apply')?.

推荐答案

使用构造函数没有简单,直接的方法。这是因为当您使用 new 关键字来调用构造函数时会发生特殊情况,因此如果您不打算这样做,则必须模拟所有这些特别的东西。它们是:

There's no simple, straightforward way to do this with a constructor function. This is because special things happen when you use the new keyword to call a constructor function, and so if you're not going to do that, you have to emulate all of those special things. They are:


  1. 创建一个新的对象实例(你正在这样做)。

  2. 设置该对象的内部原型到构造函数的 prototype 属性。

  3. 设置该对象的构造函数 property。

  4. 使用该对象实例调用构造函数作为值(您正在这样做)。

  5. 处理构造函数的特殊返回值。

  1. Creating a new object instance (you're doing that).
  2. Setting that object's internal prototype to constructor function's prototype property.
  3. Setting that object's constructor property.
  4. Calling the constructor function with that object instance as the this value (you're doing that).
  5. Handling the special return value from the constructor function.

这是关于它,但值得仔细检查规范

I think that's about it, but worth double-checking in the spec.

因此,如果你可以避免它并直接使用构造函数,我会这样做。 :-)如果你不能,你仍然可以做到这一点,它只是尴尬,涉及变通方法。 (另请参阅此相关答案这里是关于StackOverflow的,虽然我在这里覆盖了所有的基础[然后是一些]。)

So if you can avoid it and just use the constructor function directly, I'd do that. :-) If you can't, though, you can still do it, it's just awkward and involves workarounds. (See also this related answer here on StackOverflow, although I cover all of the ground here [and then some] as well.)

你最大的问题是上面的#2:设置对象的内部原型。很长一段时间,没有标准的方法来做到这一点。有些浏览器支持一个 __ proto __ 属性,所以你可以使用它,如果它在那里。好消息是ECMAScript 5引入了一种明确的方法: Object.create 。因此像Chrome这样的尖端浏览器就是这样。但是,如果您正在处理的浏览器既没有 Object.create 也没有 __ proto __ ,那么它有点难看:

Your biggest issue is #2 above: Setting the internal prototype of the object. For a long time, there was no standard way to do this. Some browsers supported a __proto__ property that did it, so you can use that if it's there. The good news is that ECMAScript 5 introduces a way to do this explicitly: Object.create. So cutting-edge browsers like Chrome will have that. But if you're dealing with a browser that has neither Object.create nor __proto__, it gets a bit ugly:

1)定义自定义构造函数。

1) Define a custom constructor function.

2)设置原型属性为真实构造函数的 prototype 属性

2) Set its prototype property to the prototype property of the real constructor function

3)用它来创建空白对象实例。

3) Use it to create a blank object instance.

为您处理原型。然后继续:

That handles the prototype for you. Then you continue with:

4)用真正的构造函数替换该实例上的构造函数属性。

4) Replace the constructor property on that instance with the real constructor function.

5)通过 apply 调用真实的构造函数。

5) Call the real constructor function via apply.

6)如果真实构造函数的返回值是一个对象,则使用它而不是你创建的那个;否则,请使用您创建的那个。

6) If the return value of the real constructor function is an object, use it instead of the one you created; otherwise, use the one you created.

这样的事情(实例):

function applyConstruct(ctor, params) {
    var obj, newobj;

    // Use a fake constructor function with the target constructor's
    // `prototype` property to create the object with the right prototype
    function fakeCtor() {
    }
    fakeCtor.prototype = ctor.prototype;
    obj = new fakeCtor();

    // Set the object's `constructor`
    obj.constructor = ctor;

    // Call the constructor function
    newobj = ctor.apply(obj, params);

    // Use the returned object if there is one.
    // Note that we handle the funky edge case of the `Function` constructor,
    // thanks to Mike's comment below. Double-checked the spec, that should be
    // the lot.
    if (newobj !== null
        && (typeof newobj === "object" || typeof newobj === "function")
       ) {
        obj = newobj;
    }

    // Done
    return obj;
}

您可以更进一步,只在必要时使用假构造函数,寻找是否首先支持 Object.create __ proto __ ,如下所示(实例):

You could take it a step further and only use the fake constructor if necessary, looking to see if Object.create or __proto__ are supported first, like this (live example):

function applyConstruct(ctor, params) {
    var obj, newobj;

    // Create the object with the desired prototype
    if (typeof Object.create === "function") {
        // ECMAScript 5 
        obj = Object.create(ctor.prototype);
    }
    else if ({}.__proto__) {
        // Non-standard __proto__, supported by some browsers
        obj = {};
        obj.__proto__ = ctor.prototype;
        if (obj.__proto__ !== ctor.prototype) {
            // Setting it didn't work
            obj = makeObjectWithFakeCtor();
        }
    }
    else {
        // Fallback
        obj = makeObjectWithFakeCtor();
    }

    // Set the object's constructor
    obj.constructor = ctor;

    // Apply the constructor function
    newobj = ctor.apply(obj, params);

    // If a constructor function returns an object, that
    // becomes the return value of `new`, so we handle
    // that here.
    if (typeof newobj === "object") {
        obj = newobj;
    }

    // Done!
    return obj;

    // Subroutine for building objects with specific prototypes
    function makeObjectWithFakeCtor() {
        function fakeCtor() {
        }
        fakeCtor.prototype = ctor.prototype;
        return new fakeCtor();
    }
}

在Chrome 6上,以上使用的Object.create ;在Firefox 3.6和Opera上,它使用 __ proto __ 。在IE8上,它使用假构造函数。

On Chrome 6, the above uses Object.create; on Firefox 3.6 and Opera, it uses __proto__. On IE8, it uses the fake constructor function.

上面是相当不合适的,但它主要处理我在这方面所知的问题。

The above is fairly off-the-cuff, but it mostly handles the issues I'm aware of in this area.

这篇关于javascript中的动态对象构造?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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