Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在JavaScript中使用参数值数组构造对象,而不是列出它们?_Javascript_Oop_Firefox Addon_New Operator_Apply - Fatal编程技术网

如何在JavaScript中使用参数值数组构造对象,而不是列出它们?

如何在JavaScript中使用参数值数组构造对象,而不是列出它们?,javascript,oop,firefox-addon,new-operator,apply,Javascript,Oop,Firefox Addon,New Operator,Apply,这可能吗?我正在创建一个基工厂函数来驱动不同类型的工厂(但有一些相似之处),我希望能够将参数作为数组传递给基工厂,然后基工厂可能会创建一个新对象的实例,通过数组填充相关类的构造函数的参数 在JavaScript中,可以使用数组通过apply方法调用具有多个参数的函数: namespace.myFunc = function(arg1, arg2) { //do something; } var result = namespace.myFunc("arg1","arg2"); //this is

这可能吗?我正在创建一个基工厂函数来驱动不同类型的工厂(但有一些相似之处),我希望能够将参数作为数组传递给基工厂,然后基工厂可能会创建一个新对象的实例,通过数组填充相关类的构造函数的参数

在JavaScript中,可以使用数组通过apply方法调用具有多个参数的函数:

namespace.myFunc = function(arg1, arg2) { //do something; }
var result = namespace.myFunc("arg1","arg2");
//this is the same as above:
var r = [ "arg1","arg2" ];
var result = myFunc.apply(namespace, r);
似乎无论如何都没有办法使用apply创建对象的实例,是吗

类似于(这不起作用):

试试这个:

var instance = {};
MyClass.apply( instance, r);
关键字“new”所做的一切就是将一个新对象传递给构造函数,然后该构造函数将成为构造函数中的this变量

根据构造函数的编写方式,您可能必须执行以下操作:

var instance = {};
var returned = MyClass.apply( instance, args);
if( returned != null) {
    instance = returned;
}
更新:一条评论说,如果有原型的话,这是行不通的。试试这个

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

newApply( MyClass, args);

解决办法呢

function MyClass(arg1, arg2) {

    this.init = function(arg1, arg2){
        //if(arg1 and arg2 not null) do stuff with args
    }

    init(arg1, arg2);
}
因此,您可以:

var obj = new MyClass();
obj.apply(obj, args);

一种可能性是使构造函数作为正常的函数调用工作

function MyClass(arg1, arg2) {
    if (!(this instanceof MyClass)) {
        return new MyClass(arg1, arg2);
    }

    // normal constructor here
}
如果将
if
语句中的条件作为正常函数调用
MyClass
(包括with
call
/
apply
,只要
参数不是
MyClass对象

现在所有这些都是等效的:

new MyClass(arg1, arg2);
MyClass(arg1, arg2);
MyClass.call(null, arg1, arg2);
MyClass.apply(null, [arg1, arg2]);

Hacks是Hacks是Hacks,但也许这一个比其他一些更优雅,因为调用语法与您想要的类似,您根本不需要修改原始类:

Function.prototype.build = function(parameterArray) {
    var functionNameResults = (/function (.{1,})\(/).exec(this.toString());
    var constructorName = (functionNameResults && functionNameResults.length > 1) ? functionNameResults[1] : "";
    var builtObject = null;
    if(constructorName != "") {
       var parameterNameValues = {}, parameterNames = [];
       for(var i = 0; i < parameterArray.length; i++) {
         var parameterName = ("p_" + i);
         parameterNameValues[parameterName] = parameterArray[i];
         parameterNames.push(("parameterNameValues." + parameterName));
       }
       builtObject = (new Function("parameterNameValues", "return new " + constructorName + "(" + parameterNames.join(",") + ");"))(parameterNameValues);
    }
    return builtObject;
};
诚然,有些人可能不喜欢修改函数对象的原型,因此您可以这样做,并将其用作函数:

function build(constructorFunction, parameterArray) {
    var functionNameResults = (/function (.{1,})\(/).exec(constructorFunction.toString());
    var constructorName = (functionNameResults && functionNameResults.length > 1) ? functionNameResults[1] : "";
    var builtObject = null;
    if(constructorName != "") {
       var parameterNameValues = {}, parameterNames = [];
       for(var i = 0; i < parameterArray.length; i++) {
         var parameterName = ("p_" + i);
         parameterNameValues[parameterName] = parameterArray[i];
         parameterNames.push(("parameterNameValues." + parameterName));
       }
       builtObject = (new Function("parameterNameValues", "return new " + constructorName + "(" + parameterNames.join(",") + ");"))(parameterNameValues);
    }
    return builtObject;
};
因此,我希望这些对某些人有用——它们允许您不使用原始的构造函数,而是通过一行简单的代码(不同于当前选择的解决方案/解决方案所需的两行代码)获得所需的内容

欢迎并感谢您的反馈


更新:另一件需要注意的事情-尝试使用这些不同的方法创建相同类型的实例,然后检查它们的构造函数属性是否相同-如果需要检查对象的类型,您可能希望这样。下面的代码最好地说明了我的意思:

function Person(firstName, lastName) {
   this.FirstName = firstName;
   this.LastName = lastName;
}

var p1 = new Person("John", "Doe");
var p2 = Person.build(["Sara", "Lee"]);

var areSameType = (p1.constructor == p2.constructor);
试试其他的一些黑客,看看会发生什么。理想情况下,你希望他们是相同的类型


警告:如注释中所述,这对于使用匿名函数语法创建的构造函数不起作用,即

MyNamespace.SomeClass = function() { /*...*/ };
除非您这样创建它们:

MyNamespace.SomeClass = function SomeClass() { /*...*/ };
我上面提供的解决方案可能对您有用,也可能对您没有用处,您需要准确地了解您正在做什么,以便为您的特定需求找到最佳解决方案,并且您需要了解如何使我的解决方案“起作用”。如果您不了解我的解决方案是如何工作的,请花时间找出答案


替代解决方案:不要忽略其他选项,这里是您可以给这只猫剥皮的其他方法之一(与上述方法有类似的警告),这一种更为深奥:

function partial(func/*, 0..n args */) {
   var args = Array.prototype.slice.call(arguments, 1);
   return function() {
      var allArguments = args.concat(Array.prototype.slice.call(arguments));
      return func.apply(this, allArguments);
   };
}

Function.prototype.build = function(args) {
   var constructor = this;
   for(var i = 0; i < args.length; i++) {
      constructor = partial(constructor, args[i]);
   }
   constructor.prototype = this.prototype;
   var builtObject = new constructor();
   builtObject.constructor = this;
   return builtObject;
};
函数部分(func/*,0..n args*/){
var args=Array.prototype.slice.call(参数,1);
返回函数(){
var allArguments=args.concat(Array.prototype.slice.call(arguments));
返回函数应用(此,所有参数);
};
}
Function.prototype.build=函数(args){
var构造函数=这个;
对于(变量i=0;i
享受吧!

注意

  • 如果没有任何参数,则可能会失败,因为构造函数函数可能依赖于参数的存在

  • 在许多情况下都会失败,特别是在本机类(如Date或Number)上调用时

我知道“eval是邪恶的”,但在这种情况下,您可能需要尝试以下方法:

function newApply(Cls, args) {
    var argsWrapper = [];
    for (var i = 0; i < args.length; i++) {
        argsWrapper.push('args[' + i + ']');
    }
    eval('var inst = new Cls(' + argsWrapper.join(',') + ');' );
    return inst;
}
函数newApply(Cls,args){
变量argsWrapper=[];
对于(变量i=0;i
就这么简单


(其工作原理与中的
Instance.New
in相同)

我不熟悉OOP术语……当MyClass不在命名空间中时,您是否试图创建namespace.MyClass的新实例?我正在尝试创建namespace.MyClass的新实例,但忘记了始终相同的命名空间。我只是想利用能够作为数组传递参数的优势在创建一个实例的时候给构造函数。啊!这就更清楚了。我仍然不知道这里是否可以使用apply——它可能——但我在Mozilla的最新js中读到了一些关于列表理解之类的有趣的东西。哦,对了,也许我可以使用它!这是一个Firefox扩展。但我并不是在尝试创建一个新的arr嗯,我正试图将数组转换为函数的参数列表。这很聪明,但似乎不起作用。至少在Firefox中不起作用,它给了我一些想法。Hrmm.FWIW,array.apply({},[2,4,6])和Number.apply({},[“3”])的简单例子似乎工作正常。但这不会将对象原型设置为MyClass.prototype,这可能是必要的。@Matthew:我喜欢,我喜欢。清理并完成工作。我删除了否决票。@Matthew,感谢编辑。编辑后,它将保留相同的原型。我希望避免对类进行更改工厂是实例tiating,但也许我不得不这么做。必须更改原始构造函数是解决这个特殊问题的一个糟糕方法
MyNamespace.SomeClass = function SomeClass() { /*...*/ };
function partial(func/*, 0..n args */) {
   var args = Array.prototype.slice.call(arguments, 1);
   return function() {
      var allArguments = args.concat(Array.prototype.slice.call(arguments));
      return func.apply(this, allArguments);
   };
}

Function.prototype.build = function(args) {
   var constructor = this;
   for(var i = 0; i < args.length; i++) {
      constructor = partial(constructor, args[i]);
   }
   constructor.prototype = this.prototype;
   var builtObject = new constructor();
   builtObject.constructor = this;
   return builtObject;
};
new myClass()
myClass.apply(something, args)
function newApply(Cls, args) {
    var argsWrapper = [];
    for (var i = 0; i < args.length; i++) {
        argsWrapper.push('args[' + i + ']');
    }
    eval('var inst = new Cls(' + argsWrapper.join(',') + ');' );
    return inst;
}