【问题标题】:Javascript - Create instance with array of argumentsJavascript - 使用参数数组创建实例
【发布时间】:2021-10-27 22:27:53
【问题描述】:

我知道使用 apply(obj,args); 调用带有参数数组的函数的可能性; 有没有办法在创建函数的新实例时使用此功能?

我的意思是这样的:

function A(arg1,arg2){
    var a = arg1;
    var b = arg2;
}

var a = new A.apply([1,2]); //create new instance using an array of arguments

希望你明白我的意思... ^^^

感谢您的帮助!

解决了!

我得到了正确的答案。为了使答案适合我的问题:

function A(arg1,arg2) {
    var a = arg1;
    var b = arg2;
}

var a = new (A.bind.apply(A,[A,1,2]))();

【问题讨论】:

  • 重要提示:该数组的第一个元素是什么并不重要。例如,new (A.bind.apply(A,['cats',1,2]))(); 也可以正常工作。原因是new 忽略了提供给绑定的this 值。
  • 使用提供的速记版本,您不需要最后两个括号'()'。因此它可能是:var a = new (A.bind.apply(A, [null].concat([1, 2])));

标签: javascript


【解决方案1】:
var wrapper = function(f, args) {
    return function() {
        f.apply(this, args);
    };
};

function Constructor() {
    this.foo = 4;
}
var o = new (wrapper(Constructor, [1,2]));
alert(o.foo);

我们获取一个函数和参数,并创建一个函数,将参数应用于具有 this 范围的函数。

然后,如果您使用 new 关键字调用它,它会传入一个新的 this 并返回它。

重要的是括号

new (wrapper(Constructor, [1,2]))

在从包装器返回的函数上调用 new 关键字,其中 as

new wrapper(Constructor, [1,2])

在包装函数上调用 new 关键字。

它需要被包装的原因是你应用它的this 是用新的关键字设置的。需要创建一个新的this 对象并将其传递给函数,这意味着您必须在函数内部调用.apply(this, array)

直播example

或者你可以使用 ES5 .bind 方法

var wrapper = function(f, args) {
    var params = [f].concat(args);
    return f.bind.apply(f, params);
};

example

【讨论】:

  • 非常好。 +1 在您的基础上构建,可能希望让 wrapper 将函数返回到具有您想要的标识符的变量,以便您可以从中调用 new,从而为 instanceof 提供您期望的结果。 jsfiddle.net/pSpz8/2
  • ...或者不是(对于我的 jsFiddle)。睡了一会儿,我发现我错过了问题的重点。
  • 谢谢,这真的很好。但问题是,生成的对象不是构造函数类型。有没有办法避免这种情况?
  • @FlashFan 没有原生的.bind 支持很难做到。或者,您可以开始将其构建到原型链中,但这只会弄乱您的原型链。请参阅已编辑的问题。
  • 重要提示:与什么数组连接并不重要,只要它只包含一个元素即可。例如,var params = ['cats'].concat(args); 也可以正常工作。原因是new 忽略了提供给绑定的this 值。
【解决方案2】:

使用 ECMAscript 5,您可以:

function createInstanceWithArguments (fConstructor, aArgs) {
    var foo = Object.create(fConstructor.prototype);
    fConstructor.apply(foo, aArgs);
    return foo;
}

【讨论】:

    【解决方案3】:

    @Raynos 回答效果很好,只是非 ES5 版本在实例化后缺少构造函数的原型。

    这是我更新的cApply 方法:

    var cApply = function(c) {
      var ctor = function(args) {
        c.apply(this, args);
      };
      ctor.prototype = c.prototype;
      return ctor;
    };
    

    可以这样使用:

    var WrappedConstructor = cApply(Constructor);
    var obj = new WrappedConstructor([1,2,3]);
    
    // or inline like this.    
    var obj2 = new (cApply(Constructor))([1,2,3]);
    

    JSFiddle 供参考。

    【讨论】:

    • 最佳解决方案 - 我调整了您的解决方案,不必传递数组,而是像平常一样使用包装的构造函数,例如。 new WrappedConstructor(1,2,3)。我还将构造函数添加到原型中以进行良好的测量 - forked jsfiddle: jsfiddle.net/pBJn4
    • 不幸的是,似乎没有办法保留返回类型的原始构造函数,这对obj instanceof Constructor 情况不利
    • 完全同意,像这样的 hack 并不是最优的。 ES5 FTW。
    【解决方案4】:

    你可以对函数进行柯里化:

    function A(arg1, arg2) {
        // ...
    }
    
    function A12() {
        A(1, 2);
    }
    

    你甚至可以建立一个咖喱工厂:

    function A_curry() {
        var args = arguments;
        return function () {
            A.apply(null, args);
        };
    }
    

    【讨论】:

      【解决方案5】:

      您可以使用Object.create() 构建新实例,然后调用实例上的构造函数:

      var args = [1,2,3];
      var instance = Object.create(MyClass.prototype);
      MyClass.apply(instance, args);
      

      或单行:

      var instance = MyClass.apply(Object.create(MyClass.prototype), args);
      

      但不要忘记return this; 中的MyClass 通过这个单行解决方案。

      如果你没有Object.create(),那么写一个很简单:

      Object.create = function (source){
          var Surrogate = function (){};
          Surrogate.prototype = source;
          return new Surrogate();
      };
      

      您可以选择编写Function.newInstance()Function.prototype.newInstance() 函数:

      Function.newInstance = function (fn, args){
          var instance = Object.create(fn.prototype);
          fn.apply(instance, args);
          return instance;
      };
      

      所以var instance = Function.newInstance(MyClass, args);.

      注意:不建议覆盖原生类。

      【讨论】:

        【解决方案6】:

        如果您将对象类名称存储在名为 className 的变量中怎么办?

        var className = 'A'
        

        根据this answer here,使用ECMAScipt5Function.prototype.bind方法,一切都变得非常干净和简单。

        带有参数数组:

        new ( Function.prototype.bind.apply( className, arguments ) );
        

        或者使用参数列表:

        new ( Function.prototype.bind.call( className, argument1, argument2, ... ) );
        

        一行,不需要包装器。

        【讨论】:

          【解决方案7】:

          我刚遇到同样的问题,也想保留目标对象的原型属性。在看了答案之后,只是想出了一个相当简单的解决方案。想我不妨分享给任何未来的寻求者:)

          // Define a pseudo object that takes your arguments as an array
          var PseudoObject = function (args) {
              TargetObject.apply(this, args);
          };
          // if you want to inherit prototype as well
          PseudoObject.prototype = new TargetObject();
          
          // Now just use the PseudoObject to instantiate a object of the the OtherObject
          var newObj = new PseudoObject([1, 2, 3]);
          

          【讨论】:

            【解决方案8】:

            现在可以使用扩展运算符来完成:

            let a = new A(...[1,2]);
            

            https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#examples

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-11-14
              • 1970-01-01
              • 2019-12-17
              • 1970-01-01
              • 2012-09-04
              • 1970-01-01
              相关资源
              最近更新 更多