在javascript中创建对象时动态控制参数

时间:2013-06-27 11:56:22

标签: javascript oop factory

我在javascript中有多个可食用的类,例如:食物,饮料,零食。 每个类都需要一组不同的参数。我有另一个工厂类,它创建一个发送给它的可食用项目的实例。

我无法弄清楚如何使用这个工厂动态选择可食用物品并传递参数(以数组形式)?

我想出了两个解决方案 - 解决方案1:

var factory = function(eatable, argumentList){
  var obj = new eatable(argumentList);
  return obj
};

这是一个问题,因为argumentList是一个数组。

解决方案2

var factory = function(eatable, argumentList){
  var obj =  eatable.apply({}, argumentList);
  return obj
};

这并不能真正创建一个可食用类型的对象。

我真正想要的效果 假设我能够将argumentList转换为js参数类型对象,然后 -

var obj = new eatable(argumentList.toArguments());
obj instanceOf eatable; // should return true

请帮忙!

5 个答案:

答案 0 :(得分:4)

啊,是的。我之前遇到过这个问题 - 你在JavaScript中can't use new and apply together。之前曾提出过类似的问题:Use of .apply() with 'new' operator. Is this possible?

问题非常明显 - new是一个关键字,而不是一个函数;并且apply只能用于某个函数。如果new是函数而不是keyword,那么我们可以将其与apply结合使用。

要了解如何操作,让我们创建一个名为new的函数,该函数完全符合关键字new的作用:

Function.prototype.new = (function () {
    function Factory(constructor, args) {
        return constructor.apply(this, args);
    }

    return function() {
        Factory.prototype = this.prototype;
        return new Factory(this, arguments);
    };
}());

现在不是按如下方式调用构造函数:

var object = new constructor(arg1, ...);

您可以按如下方式调用构造函数:

var object = constructor.new(arg1, ...);

这样做有什么好处?嗯,这很简单。由于new现在是一个函数而不是关键字,因此您可以将其与apply结合使用,如下所示:

var object = Function.new.apply(constructor, [arg1, ...]);

因此,您的可食用工厂功能现在变为:

var factory = function(eatable, argumentList) {
    var obj = Function.new.apply(eatable, argumentList);
    return obj;
};

编辑:如果您的所有工厂功能都是eatable构造函数和argumentList并返回new.apply(eatable, argumentList),那么Bergi在他的评论中指出可以如下定义factory

var factory = Function.apply.bind(Function.new);

希望这会有所帮助。

答案 1 :(得分:3)

您可以使用Object.create正确设置原型链:

function factory(eatable, argumentList){
    var obj = Object.create(eatable.prototyope);
    return eatable.apply(obj, argumentList) || obj;
}

这基本上是new operator的作用。

答案 2 :(得分:1)

您可以定义函数init来初始化对象。

function Eatable(){

}

Eatable.prototype.init = function(/** arg1, arg2, arg3 **/){
    //  initialize object
}

在工厂功能

var eatable = new Eatable();
eatable.init.apply(eatable, /** pass arguments array here **/);
return eatable;

答案 3 :(得分:0)

您必须提供要应用的上下文,上下文是您尝试应用参数的对象。您当前传递的上下文{}的类型为Object

var factory = function(eatable, argumentList){
  var obj =  eatable.apply(new Eatable(), argumentList);
  return obj
};

我不能使用没有多态性的工厂,所以如果你没有以扩展Eatalbe对象的方式创建那些 eatables ,你就无法做到。

答案 4 :(得分:0)

实现此目的的另一种方法如下 -

var _bind = Function.prototype.bind;
var factory = function(_constructor, _argumentList){
  var obj = _bind.apply(_constructor, [null].concat(_argumentList));
  return obj
};