В Javascript есть эквивалент .apply, который не меняет значение этого? - PullRequest
44 голосов
/ 09 марта 2011

Кажется достаточно просто, я хочу вызвать функцию с массивом аргументов. Конечно, я могу сказать func.apply(this, ['some', 'arguments']);, но это изменит значение this внутри func. Любая идея, как это сделать, не меняя его?

Ответы [ 5 ]

29 голосов
/ 09 марта 2011

Вы не можете , потому что this работает в JavaScript . Продолжаемый читать:

В соответствии с разделом «Вход в контекст выполнения» спецификации ECMAScript: при вызове функции значение this определяется тем, что слева (так называемая активация ) объект ). Давайте создадим функцию с именем steve и поместим его в объект:

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

… когда мы называем Стива obj.method(), его this равен obj, потому что obj был объектом активации.

Сложный случай, когда ничего находится слева от вызова функции:

steve(); // Who am I ?!

Слева от вызова функции ничего - по сути, это null - поэтому значение this устанавливается равным значению по умолчанию для глобального объекта (window в веб-браузерах , global в Node.js и т. Д.).

Таким образом, вы фактически устанавливаете функцию this каждый раз, когда вызываете ее.

P.S. вызов steve.apply(null, []) эквивалентен вызову steve().

10 голосов
/ 06 сентября 2016

Обратите внимание, что в ES6 вы также можете написать:

func(...someArray)

Здесь this становится Window внутри func, что бесполезно.Но если вы напишите:

obj.func(...someArray)

this внутри func будет obj.

Это может быть функция, которую я искал 5 лет назад, но это было5 лет назад, так что кто помнит:)

3 голосов
/ 09 марта 2011

Значение this не является загадкой при вызове функции, в зависимости от того, как она вызывается "нормально" (без call или 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, []);
2 голосов
/ 09 марта 2011

Если вы вызываете одну функцию, передайте null.

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

Если вы вызываете функцию, которая является методом объекта, передайте этот объект.

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

Чтобы соответствовать как , это работает.

0 голосов
/ 09 марта 2011

То, что вы хотите, не имеет особого смысла.

В стандарте ecmascript this определяется следующим образом:

11.1.1 Это ключевое слово Это ключевое слово this оцениваетк значению ThisBinding текущего контекста выполнения.

Разрешение thisBinding для контекста выполнения функций указывается следующим образом:

10.4.3 Ввод кода функции Theследующие шаги выполняются, когда элемент управления входит в контекст выполнения для кода функции, содержащегося в объекте функции F, вызывающий объект предоставил thisArg и предоставленный вызывающим абонентом argumentsList:

  1. Если код функции является строгим кодом, установите ThisBindingк этому Arg.
  2. Иначе, если thisArg имеет значение null или не определено, установите ThisBinding для глобального объекта.
  3. В противном случае, если Type (thisArg) не является Object, установите для ThisBinding ToObject (thisArg).
  4. В противном случае установите ThisBinding на thisArg.
  5. Пусть localEnv будет результатом вызова NewDeclarativeEnvironment, передав в качестве аргумента значение внутреннего свойства [[Scope]] для F.
  6. Установите для LexicalEnvironment значение localEnv.
  7. Установите для VariableEnvironment значение localEnv.
  8. Пусть code будет значением внутреннего свойства F [[Code]].
  9. Выполните реализацию привязки декларации, используя код кода функции и argumentsList, как описано в 10.5.

Другими словами: либо вы указываете его, либо он автоматически устанавливается на глобальныйобъект.Он никогда не унаследует привязку this от родительской области видимости, поэтому единственный способ передать thisBindiong родительской области своим дочерним элементам - это либо

  1. сохранить его в локальной переменной в родительской области, напримерvar self = this
  2. введите его с помощью call / apply, как код, который вы задали в своем вопросе.
...