3

我在 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

请帮忙!

4

5 回答 5

4

是的。我以前遇到过这个问题——你不能newapply在 JavaScript 中同时使用and 。之前有人问过类似的问题:Use of .apply() with 'new' operator。这可能吗?

问题很明显——new是关键字,而不是函数;并且apply只能用于函数。ifnew是一个函数而不是 a keywordthen 我们可以将它与 结合使用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构造函数和 anargumentList并返回,new.apply(eatable, argumentList)那么正如 Bergi 在他的评论中指出的那样,您可以定义factory如下:

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

希望这有帮助。

于 2013-06-27T14:20:33.203 回答
3

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

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

这基本上是new运营商所做的。

于 2013-06-27T14:00:23.643 回答
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;
于 2013-06-27T12:05:54.943 回答
0

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

var _bind = Function.prototype.bind;
var factory = function(_constructor, _argumentList){
  var obj = _bind.apply(_constructor, [null].concat(_argumentList));
  return obj
};
于 2014-07-22T10:41:57.497 回答
0

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

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

我不能使用没有多态性的工厂,所以如果你没有以它们扩展对象的方式创建那些可食用Eatalbe的东西,你将无法做到这一点。

于 2013-06-27T12:02:27.147 回答