javascript中的动态对象构造? [英] dynamic object construction in 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:
- 创建一个新的对象实例(你正在这样做)。
- 设置该对象的内部原型到构造函数的
prototype
属性。 - 设置该对象的
构造函数
property。 - 使用该对象实例调用构造函数作为
此
值(您正在这样做)。 - 处理构造函数的特殊返回值。
- Creating a new object instance (you're doing that).
- Setting that object's internal prototype to constructor function's
prototype
property. - Setting that object's
constructor
property. - Calling the constructor function with that object instance as the
this
value (you're doing that). - 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屋!