【问题标题】:Why invoke "apply" instead of calling function directly?为什么调用“应用”而不是直接调用函数?
【发布时间】:2011-08-21 15:38:08
【问题描述】:

在查看 raphael 或 g.raphael 或其他库的源代码时,我注意到开发人员会这样做:

var val = Math.max.apply(Math, data_array);

为什么不直接调用函数呢,比如:

var val = Math.max(data_array);

谢谢。

【问题讨论】:

  • 好的,所以我看到 Math.max 需要两个参数,所以我只是调用的示例 Math.max(array) 不起作用。所以,我想问题是我的问题中的第一行代码如何在 data_array 的每个元素上调用“max”?
  • Javascript 的 .apply.call ftw!!

标签: javascript splat


【解决方案1】:

通常您会使用apply()call() 来设置调用函数所属的上下文或对象。然后,该函数有效地成为该对象/上下文的方法,如果您需要访问上下文的字段,这将很有帮助。

这是 Javascript 原生调用函数的方式:

  1. 从参数 1 到末尾创建一个参数列表 (argList)
  2. 第一个参数是thisValue
  3. 将此设置为 thisValue 并将 argList 作为其参数列表来调用函数

参考:Understanding JavaScript Function Invocation and "this"Yehuda Katz

因此,当直接调用函数时,实际上是在隐式地将默认上下文传递给函数。当您未使用 call()apply() 指定时,Javascript 将 'window''undefined' 作为上下文传递

answer 还提供了一个示例,可能有助于理解用法

【讨论】:

    【解决方案2】:

    .apply 通常用于意图调用带有参数值列表的可变参数函数,例如

    Math.max([value1[,value2, ...]]) 函数返回零个或多个数字中的最大值。

    Math.max(10, 20); // 20
    Math.max(-10, -20); // -10
    Math.max(-10, 20); // 20
    

    Math.max() 方法不允许您传入数组。如果您有一个需要获取最大值的列表,您通常会使用Function.prototype.apply() 调用此函数,例如

    Math.max.apply(null, [10, 20]); // 20
    Math.max.apply(null, [-10, -20]); // -10
    Math.max.apply(null, [-10, 20]); // 20
    

    但是,从 ECMAScript 6 开始,您可以使用 spread operator

    扩展运算符允许在需要多个参数(用于函数调用)或多个元素(用于数组字面量)的地方扩展表达式。

    Math.max(...[10, 20]); // 20
    Math.max(...[-10, -20]); // -10
    Math.max(...[-10, 20]); // 20
    

    当使用可变参数调用函数时,你甚至可以添加额外的值,例如

    Math.max(...[10, 20], 50); // 50
    Math.max(...[-10, -20], 50); // 50
    

    【讨论】:

      【解决方案3】:

      为什么调用“apply”而不是直接调用函数?让我们来个sn-p:

      var obj = {a: "apply"};
      func.call(obj, "parameter");
      function func(para) {
          if(this.a === "apply"){
              console.log('apply'); 
           }
      } 
      

      这里我们可以看到我们在一个函数中使用'this'(上下文),如果我们直接调用一个函数而不是我们没有任何上下文,那么它将使用window上下文,这是错误的。因此,如果您在函数中使用上下文而不是使用 apply 方法。

      【讨论】:

        【解决方案4】:

        我认为Mozilla Docs的解释描述得很好:

        您可以分配不同的 this 对象 调用现有函数时。 this 指的是当前对象, 调用对象。通过应用,您可以 写一次方法然后继承 它在另一个对象中,没有 重写新的方法 对象。

        apply 与 call 非常相似,除了 对于它支持的参数类型。 您可以改用参数数组 一组命名的参数。和 应用,您可以使用数组文字, 例如,fun.apply(this, [name, value]) 或 Array 对象,用于 例如,fun.apply(这个,新的 数组(名称,值))。

        关于参数:

        thisArg 确定 fun 中 this 的值。如果 thisArg 为 null 或 未定义,this 将是全局的 目的。否则,这将是相等的 到 Object(thisArg) (这是 thisArg 如果 thisArg 已经是一个对象,或者一个 如果 thisArg,则为字符串、布尔值或数字 是的原始值 对应类型)。因此它是 总是如此 typeof this == 函数执行时的“对象”。

        argsArray 对象的参数数组,指定参数 fun 应该被调用,或者 null 或者 如果没有参数应该是未定义的 提供给函数。

        文档提供了一个很好的应用用例示例。在下面的示例中,apply 用于链接构造函数:

        function product(name, value)
        {
          this.name = name;
          if (value >= 1000)
            this.value = 999;
          else
            this.value = value;
        }
        
        function prod_dept(name, value, dept)
        {
          this.dept = dept;
          product.apply(this, arguments);
        }
        prod_dept.prototype = new product();
        
        // since 5 is less than 1000 value is set
        var cheese = new prod_dept("feta", 5, "food");
        
        // since 5000 is above 1000, value will be 999
        var car = new prod_dept("honda", 5000, "auto");
        

        请注意,在prod_dept 构造函数中,提供的this 引用prod_dept 对象,arguments 是传递给product 构造函数的参数数组。

        【讨论】:

        • prod_dept.prototype = new product();此行完全不需要,请排除复杂性!
        【解决方案5】:

        Math.max 默认不接受列表。 "apply" 允许您将列表解压缩为参数,以便 max 正常工作。

        【讨论】:

          猜你喜欢
          • 2012-08-30
          • 2016-09-25
          • 2012-08-04
          • 1970-01-01
          • 1970-01-01
          • 2013-07-09
          • 2011-05-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多