47

看起来很简单,我想用参数数组调用一个函数。当然,我可以说func.apply(this, ['some', 'arguments']);,但这会改变thisinside的价值func。知道如何在不改变它的情况下做到这一点吗?

4

5 回答 5

31

你不能,因为thisJavaScript 的工作方式。继续阅读:

通过 ECMAScript 规范的“进入执行上下文”部分:当你调用一个函数时,它的值this取决于它剩下的(称为激活对象)。让我们创建一个名为 steve 的函数,并将他放在一个对象中:

function steve(){}
var obj = { method: steve };

…当我们称 steve as 时obj.method(),他的thisis obj,因为obj是激活对象。

棘手的情况是函数调用的左侧没有任何内容:

steve(); // Who am I ?!

函数调用的左边没有任何东西——实际上,它是——所以null 值this被设置为全局对象的默认值(window在 Web 浏览器中,global在 Node.js 中等)。

因此,实际上,this您每次调用它时都在设置一个函数。

PS callsteve.apply(null, [])相当于 call steve()

于 2011-03-09T14:45:38.597 回答
13

请注意,在 ES6 中,您还可以编写:

func(...someArray)

这里this变成了Windowinside func,没有用。但是如果你写:

obj.func(...someArray)

this在里面funcobj

这可能是我 5 年前一直在寻找的功能,但那是 5 年前的事了,所以谁记得 :)

于 2016-09-06T07:31:11.640 回答
3

调用函数时的值this并不神秘,具体取决于“通常”的调用方式(不带callor apply):

func(); // `this` is the global object, or undefined in ES5 strict mode
obj.func(); // `this` is `obj`

因此,为避免“更改” 的值this,只需将正确的值传递给apply,具体取决于您如何“正常”调用它:

func.apply(undefined, []); // global object, or undefined in ES5 strict mode
obj.func.apply(obj, []);
于 2011-03-09T14:56:12.147 回答
2

如果您单独调用一个函数,请传递null.

func.apply(null, ['some', 'arguments']);

如果您正在调用作为对象方法的函数,请传递该对象。

var arr = [];
arr.push.apply(arr, ['some', 'arguments']);

为了匹配这是如何工作的。

于 2011-03-09T14:30:36.840 回答
0

你想要的没有多大意义。

在 ecmascript 标准this中是这样定义的:

11.1.1 this 关键字 this 关键字计算为当前执行上下文的 ThisBinding 的值。

函数执行上下文的 thisBinding 解析是这样指定的:

10.4.3 进入函数代码 当控制进入函数对象F中包含的函数代码的执行上下文时,调用者提供thisArg和调用者提供argumentsList时,执行以下步骤:

  1. 如果函数代码是严格代码,则将 ThisBinding 设置为 thisArg。
  2. 否则,如果 thisArg 为 null 或未定义,则将 ThisBinding 设置为全局对象。
  3. 否则,如果 Type(thisArg) 不是 Object,则将 ThisBinding 设置为 ToObject(thisArg)。
  4. 否则将 ThisBinding 设置为 thisArg。
  5. 让 localEnv 成为调用 NewDeclarativeEnvironment 的结果,并将 F 的 [[Scope]] 内部属性的值作为参数传递。
  6. 将 LexicalEnvironment 设置为 localEnv。
  7. 将变量环境设置为 localEnv。
  8. 令 code 为 F 的 [[Code]] 内部属性的值。
  9. 使用功能代码代码和argumentList 执行声明绑定实例化,如10.5 中所述。

换句话说:要么你指定它,要么它被自动设置为全局对象。它永远不会从其父范围继承 this 绑定,因此将父范围的 thisBindiong 赋予其子级​​的唯一方法是

  1. 将其保存在父范围内的局部变量中,例如 varself = this
  2. 像您在问题中提供的代码一样,通过 call/apply 注入它。
于 2011-03-09T14:48:59.690 回答