.apply(Math, arrayName)在JS中是如何工作的?

How does .apply(Math, arrayName) work in JS?

本文关键字:何工作 工作 JS Math arrayName apply      更新时间:2023-09-26

关于如何在javascript中找到值数组的最小值或最大值,有多个stackoverflow问题。这不是那个问题。

我想知道为什么传递.apply()奇怪的东西作为this参数仍然有效。尽管Aaron Crane写了一篇关于Math对象的API是如何变成现在这个样子的博文,但仍有一些问题没有得到解答。

下面的每个代码片段都可以工作。我的问题是,怎么做?到底发生了什么分配给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

当使用.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);

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

仅供参考,在jQuery中$.when.apply($, arr)也经常出现类似的问题,在其实现中也不使用this参数,因此可以将其称为$.when.apply(null, arr)甚至$.when.apply("foo", arr)。就我个人而言,我更喜欢通过"技术正确"考试。参数


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

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

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

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

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

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

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

比如说,你有一个这样的对象:

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

如果你调用obj.b(),你将得到1作为返回值,因为this在这个场景中是通过调用b来定义的,obj在它前面(this === obj)。要更改它,您可以使用apply:

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

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

BUT:如果你有一个函数,没有内部使用this,那么this的值是什么并不重要。所以你可以调用:

obj.c();

或下列之一:

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

但是你总是会得到相同的结果3。这就像设置了一个永远不会用到的变量。不管它的价值是多少,都不会影响结果。

所以显然Math.min不使用this,因此在传递"无效"上下文时不会中断。

这(可以这么说)是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,所以你可以把它分配给任何你想要的。