行是知之始,知是行之成。这篇文章主要讲述将.apply()与'
new'
运算符一起使用。这可能吗?相关的知识,希望能为你提供帮助。
在javascript中,我想创建一个对象实例(通过new
运算符),但是将任意数量的参数传递给构造函数。这可能吗?
我想做的是这样的事情(但下面的代码不起作用):
function Something(){
// init stuff
}
function createSomething(){
return new Something.apply(null, arguments);
}
var s = createSomething(a,b,c);
// 's' is an instance of Something
【将.apply()与' new' 运算符一起使用。这可能吗()】答案
根据这里的回答,很明显没有内置的方法用
.apply()
操作符调用new
。然而,人们提出了一些非常有趣的解决方案。我首选的解决方案是this one from Matthew Crumley(我已将其修改为通过
arguments
属性):var createSomething = (function() {
function F(args) {
return Something.apply(this, args);
}
F.prototype = Something.prototype;
return function() {
return new F(arguments);
}
})();
答案使用ECMAScript 5,qazxsw poi的东西变得非常干净:
Function.prototype.bind
它可以使用如下:
function newCall(Cls) {
return new (Function.prototype.bind.apply(Cls, arguments));
// or even
// return new (Cls.bind.apply(Cls, arguments));
// if you know that Cls.bind has not been overwritten
}
甚至直接:
var s = newCall(Something, a, b, c);
这和
var s = new (Function.prototype.bind.call(Something, null, a, b, c));
var s = new (Function.prototype.bind.apply(Something, [null, a, b, c]));
是唯一一直有效的,即使是像eval-based solution这样的特殊构造函数:Date
编辑
一点解释:我们需要在一个带有有限数量参数的函数上运行
var date = newCall(Date, 2012, 1);
console.log(date instanceof Date);
// true
。 new
方法允许我们这样做:bind
var f = Cls.bind(anything, arg1, arg2, ...);
result = new f();
参数无关紧要,因为anything
关键字重置了new
的上下文。但是,出于语法原因需要它。现在,对于f
调用:我们需要传递可变数量的参数,所以这就是诀窍:bind
让我们把它包装在一个函数中。
var f = Cls.bind.apply(Cls, [anything, arg1, arg2, ...]);
result = new f();
作为arugment 0传递,所以它将是我们的Cls
。anything
实际上,根本不需要临时的
function newCall(Cls /*, arg1, arg2, ... */) {
var f = Cls.bind.apply(Cls, arguments);
return new f();
}
变量:f
最后,我们应该确保
function newCall(Cls /*, arg1, arg2, ... */) {
return new (Cls.bind.apply(Cls, arguments))();
}
真的是我们需要的。 (bind
可能已被覆盖)。所以用Cls.bind
替换它,我们得到如上所述的最终结果。另一答案我刚遇到这个问题,我解决了这个问题:
function Something() {
// init stuff
return this;
}
function createSomething() {
return Something.apply( new Something(), arguments );
}
var s = createSomething( a, b, c );
是的,它有点难看,但它解决了问题,而且很简单。
另一答案如果您对基于eval的解决方案感兴趣
function instantiate(ctor) {
switch (arguments.length) {
case 1: return new ctor();
case 2: return new ctor(arguments[1]);
case 3: return new ctor(arguments[1], arguments[2]);
case 4: return new ctor(arguments[1], arguments[2], arguments[3]);
//...
default: throw new Error('instantiate: too many parameters');
}
}function Thing(a, b, c) {
console.log(a);
console.log(b);
console.log(c);
}var thing = instantiate(Thing, 'abc', 123, {x:5});
另一答案另请参阅CoffeeScript如何做到这一点。
function createSomething() {
var q = [];
for(var i = 0;
i <
arguments.length;
i++)
q.push("arguments[" + i + "]");
return eval("new Something(" + q.join(",") + ")");
}
变为:
s = new Something([a,b,c]...)
另一答案这有效!
var s;
s = (function(func, args, ctor) {
ctor.prototype = func.prototype;
var child = new ctor, result = func.apply(child, args);
return Object(result) === result ? result : child;
})(Something, [a, b, c], function(){});
另一答案这个构造函数方法可以使用和不使用
var cls = Array;
//eval('Array');
dynamically
var data = https://www.songbingjia.com/android/[2];
new cls(...data);
关键字:new
它假设支持
function Something(foo, bar){
if (!(this instanceof Something)){
var obj = Object.create(Something.prototype);
return Something.apply(obj, arguments);
}
this.foo = foo;
this.bar = bar;
return this;
}
,但如果你支持旧的浏览器,你可以随时填充。 Object.create
。这是一个See the support table on MDN here。
另一答案没有ES6或polyfill的解决方案:
JSBin to see it in action with console output
产量演示{arg1:“X”,arg2:“Y”,arg3:“Z”}......或“更短”的方式:
var obj = _new(Demo).apply(["X", "Y", "Z"]);
function _new(constr)
{
function createNamedFunction(name)
{
return (new Function("return function " + name + "() { };
"))();
}var func = createNamedFunction(constr.name);
func.prototype = constr.prototype;
var self = new func();
return { apply: function(args) {
constr.apply(self, args);
return self;
} };
}function Demo()
{
for(var index in arguments)
{
this['arg' + (parseInt(index) + 1)] = arguments[index];
}
}
Demo.prototype.tagged = true;
console.log(obj);
console.log(obj.tagged);
编辑: 我认为这可能是一个很好的解决方案:
var func = new Function("return function " + Demo.name + "() { };
")();
func.prototype = Demo.prototype;
var obj = new func();
Demo.apply(obj, ["X", "Y", "Z"]);
另一答案您不能使用
this.forConstructor = function(constr)
{
return { apply: function(args)
{
let name = constr.name.replace('-', '_');
let func = (new Function('args', name + '_', " return function " + name + "() { " + name + "_.apply(this, args);
}"))(args, constr);
func.constructor = constr;
func.prototype = constr.prototype;
return new func(args);
}};
}
运算符调用具有可变数量参数的构造函数。你可以做的是稍微改变构造函数。代替:
new
改为:
function Something() {
// deal with the "arguments" array
}
var obj = new Something.apply(null, [0, 0]);
// doesn't work!
或者如果必须使用数组:
function Something(args) {
// shorter, but will substitute a default if args.x is 0, false, "" etc.
this.x = args.x || SOME_DEFAULT_VALUE;
// longer, but will only put in a default if args.x is not supplied
this.x = (args.x !== undefined) ? args.x : SOME_DEFAULT_VALUE;
}
var obj = new Something({x: 0, y: 0});
另一答案CoffeeScript中的
function Something(args) {
var x = args[0];
var y = args[1];
}
var obj = new Something([0, 0]);
:Matthew Crumley's solutions
要么
construct = (constructor, args) ->
F = ->
constructor.apply this, args
F.prototype = constructor.prototype
new F
另一答案
createSomething = (->
F = (args) ->
Something.apply this, args
F.prototype = Something.prototype
return ->
new Something arguments
)()
如果您的目标浏览器不支持ECMAScript 5
function createSomething() {
var args = Array.prototype.concat.apply([null], arguments);
return new (Function.prototype.bind.apply(Something, args));
}
,则代码将不起作用。但这不太可能,请参阅Function.prototype.bind
。另一答案修改@Matthew回答。在这里,我可以传递任意数量的参数来照常运行(不是数组)。 'Something'也没有硬编码:
compatibilty table
另一答案这是一个通用的解决方案,可以使用参数数组调用任何构造函数(除了在被称为函数时表现不同的本机构造函数,如
Function.prototype.bind
,String
,Number
等):Date
通过调用
function construct(constructor, args) {
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 可以将Google Appengine的管理控制台集成到spring-boot项目中吗()
- 将可执行文件移动到其他位置后,将忽略app.exe.manifest设置
- 没有关于AppSecret Proof for Server API调用的文档()
- Gulp(最大化站点速度的Web开发人员的秘密武器)
- 使用Elm使你的Web前端更可靠
- 使用普通的旧Ruby对象构建流畅的Rails组件
- 如果你对电子商务很认真,请使用Magento
- HTTP请求测试(开发人员的生存工具)
- 使用Redux在JavaScript中保持不变