【问题标题】:How does .apply(Math, arrayName) work? (javascript).apply(Math, arrayName) 是如何工作的? (javascript)
【发布时间】:2014-07-02 21:49:16
【问题描述】:

morethanonestackoverflow 问题关于如何在 javascript 中找到一组值的最小值或最大值。这不是那个问题。

我想知道为什么将 .apply() 奇怪的东西作为 this 参数传递仍然有效。尽管来自 Aaron Crane 的 a good blog post 讲述了 Math 对象的 API 是如何变成现在这样的,但仍有一些问题没有得到解答。

以下每个代码 sn-ps 都有效。我的问题是,怎么做?分配给this 的具体情况如何使这些工作都发挥作用?

标准结构

var values = [45, 46, 47]
var min = Math.min.apply(Math, values);
alert(min); //45

一个奇怪的结构,但范围可能很棘手......

var values = [45, 46, 47]
var min = Math.min.apply(this, values);
alert(min); //45

有点奇怪

var values = [45, 46, 47]
var min = Math.min.apply(global, values);
alert(min); //45

仍然很奇怪,但也许还可以 b/c 浏览器

var values = [45, 46, 47]
var min = Math.min.apply(window, values);
alert(min); //45

很奇怪

var values = [45, 46, 47]
var min = Math.min.apply(null, values);
alert(min); //45

真的很奇怪

var values = [45, 46, 47]
var min = Math.min.apply(undefined, values);
alert(min); //45

【问题讨论】:

  • Math.min 不会以任何方式使用this,所以实际上你通过它并不重要,它并不在乎。
  • 作为thisArg 传递的值仅对function 重要,前提是它依赖于具有特定值的this。还有,Math.min()doesn't need to reference this at all
  • apply 的第一个参数是函数中应该用作this 的值。由于Math.min 不会使用 this 做任何事情,逻辑上你通过参数传递的this 一点都不重要……你不妨传递"foobar" 或@ 987654348@ 作为apply 的第一个参数。

标签: javascript this


【解决方案1】:

当使用.apply() 时,第一个参数控制函数执行时this 指针值的设置。在许多情况下,this 值至关重要。在少数情况下,this 值根本不会在函数实现中使用(通常称为不对实例数据进行操作的静态函数)。当不使用this 时,this 设置为什么无关紧要,因此.apply() 的第一个参数设置为什么无关紧要。

因此,在您的具体情况下,Math.min()Math.max()(可能还有所有Math.xxx() 函数)根本不使用this 指针,因为它们基本上都是不能操作的静态函数实例数据。因此,设置什么并不重要,因此您可以将任何您想要的作为第一个参数传递给Math.min.apply(),并且不会改变函数调用的结果。


我认为仍然应该在那里传递正确的值,即Math,因为当您执行正常操作时,this 将是:

Math.min(x, y);

所以,当使用.apply() 时,要向Math.min() 呈现与上述代码完全相同的情况,您可以这样做:

var arr = [x, y];
Math.min.apply(Math, arr);

IMO,这促进了正确的习惯和正确思考第一个参数应该是什么,因为它在其他情况下很重要。

仅供参考,jQuery 中的$.when.apply($, arr) 经常出现类似的问题,它在其实现中也没有使用this 参数,因此可以将其称为$.when.apply(null, arr) 甚至$.when.apply("foo", arr)。就个人而言,我更喜欢传递第一个“技术上正确”的论点。


仅供参考,在现代 Javascript (ES2015+) 中,对于这种特定类型的操作,您可以使用 spread syntax 代替 .apply()

const arr = [1,2];
const maxVal = Math.max(...arr);

而且,数组会通过扩展语法自动为您解压缩成单独的参数。并且没有决定将什么传递给.apply() 的第一个参数,因为您只是在进行完全相同的Math.max() 函数调用,而没有任何操作。

【讨论】:

  • 添加了对 ES2015 扩展语法的引用。
【解决方案2】:

TL;DR - Math.min()Math.max() 实际上并没有使用传递给它们的 this 参数,这只是让它们接受参数数组的技巧,因为本机 API 只指定了一个列表的变量。 .apply() 可以接受参数数组,这就是使用它的原因。

我的猜测是 Math 作为 this 参数传入只是为了清洁。

感谢@Jonathan Lonowski 和@Niet the Dark Absol。

【讨论】:

    【解决方案3】:

    apply 对其第一个参数所做的只是为调用它的函数设置上下文 (this)。

    假设你有一个这样的对象:

    var obj = {
        a: 1,
        b: function () {
            return this.a;
        },
        c: function () {
            return 3;
        }
    }
    

    如果你调用obj.b(),你会得到1作为返回值,因为在这种情况下this是通过调用b定义的,前面加上objthis === obj)。要改变它,你可以使用apply:

    obj.b.apply({a:2});
    

    这将返回 2,因为您现在将 this 显式设置为 {a:2}

    但是:如果你有一个函数,它不会在内部使用this,那么this 有什么值并不重要。所以你可以打电话:

    obj.c();
    

    或其中之一:

    obj.apply.c(null);
    obj.apply.c(undefined);
    obj.apply.c("xyz");
    

    但是你总是会得到相同的结果3。这就像设置一个你从不使用的变量。不管是什么值,都不影响结果。

    显然Math.min 没有使用this,因此在传递“无效”上下文时不会中断。

    【讨论】:

      【解决方案4】:

      这(可以这么说)是 JavaScript 的一个棘手部分。

      当你有一个函数时,有一个名为this 的神奇变量。根据您调用函数的方式,其上下文设置不同。

      function myFunction() {
        return this;
      }
      
      var myObject = {
        fn: function() {
          return this;
        }
      };
      
      myFunction();  // the global object. `window` in browsers, `global` in Node.js
      myFunction.apply(Math);  // Math
      myFunction.apply({ hello: "world" });  // { hello: "world" }
      
      myObject.fn();               // myObject
      myObject.fn.apply(myObject); // myObject
      myObject.fn.apply(Math);     // Math
      

      您上面的示例有效的原因是因为min 根本不使用this,因此您可以将其分配给您想要的任何东西。

      【讨论】:

        猜你喜欢
        • 2016-04-20
        • 2015-12-01
        • 1970-01-01
        • 2020-07-28
        • 2020-04-12
        • 2020-09-17
        • 1970-01-01
        • 2013-04-04
        • 2011-12-16
        相关资源
        最近更新 更多