В Javascript есть эквивалент .apply, который не меняет значение this?

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


person JussiR    schedule 09.03.2011    source источник
comment
Ну, вы можете передать null в качестве первого аргумента. Однако на что должно ссылаться this внутри func ?   -  person jAndy    schedule 09.03.2011
comment
Вопрос недостаточно ясен. Пожалуйста, дайте больше кода.   -  person artyom.stv    schedule 09.03.2011
comment
Похоже, вы используете this внутри функции таким образом, что его нельзя использовать.   -  person Lightness Races in Orbit    schedule 09.03.2011
comment
Хорошо, теперь я понял. В моем случае у меня был прототип функции объекта, который я хотел вызвать с помощью .apply(). Я предполагал, что функция будет каким-то образом привязана к своему объекту, поэтому не хотел ее менять, как это делает apply, но видимо такой связи нет и apply() просто имеет дело с функцией, которую она вызывает.   -  person JussiR    schedule 10.03.2011


Ответы (5)


Вы не можете этого сделать, из-за того, как this работает в JavaScript. Читай дальше:

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

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().

person s4y    schedule 09.03.2011
comment
С ES5 это не так. Значение this не определено (не нулевое), и оно не изменяется на глобальный объект (на самом деле это неверно для операторов with, но я пока их проигнорирую). Для механизмов ES3 и ES5, за исключением операторов with, steve.apply(undefined, []) и steve() эквивалентны, хотя их поведение в ES3 и ES5 различается. - person gsnedders; 09.03.2011
comment
@gsnedders, спасибо! То, что я нашел в спецификации (раздел 10.4.3), описывает установку this к глобальному объекту, и null/undefined эквивалентны. Можете ли вы показать мне, где описано новое поведение? - person s4y; 09.03.2011
comment
Люблю ответы, которые ссылаются на спецификацию для обеспечения контекста. - person Dwight Gunning; 06.09.2016
comment
Что произойдет, если я захочу вызвать объект функции, который уже привязан к объекту, без изменения «this»? Например, var handler = MyFunction.bind(myObject); Здесь я создал объект функции, уже связанный с myObject, как объект this; Теперь я хочу вызвать обработчик из другой части моего кода, которая даже не знает о существовании myObject. handler.call(null, params) уничтожит это, нет? Что произойдет, если я назову его handler.call(undefined, params)? - person Thanasis Ioannidis; 02.05.2017
comment
@ThanasisIoannidis: связанная функция должна игнорировать значение this, которое она получает во время вызова. this по-прежнему будет тем, что вы передали .bind(). - person s4y; 04.05.2017

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

func(...someArray)

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

obj.func(...someArray)

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

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

person JussiR    schedule 06.09.2016

Значение 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, []);
person David Tang    schedule 09.03.2011
comment
null не работает для глобального объекта в браузерах, реализующих ES5, так как тогда в вызываемой функции будет нулевое значение. - person gsnedders; 09.03.2011
comment
@gsnedders, будьте осторожны, когда говорите es5, потому что это верно только в строгом режиме. Тем не менее, я изменил свой ответ, указав неопределенное значение для оптимальной совместимости. ваше здоровье. - person David Tang; 10.03.2011
comment
Хм, примечание под Function.prototype.apply оказывается несколько вводящим в заблуждение, если глубже следовать алгоритму… Значение thisArg передается без изменений как значение this. Это отличие от версии 3, где неопределенный или нулевой thisArg заменяется глобальным объектом, а ToObject применяется ко всем остальным значениям, и этот результат передается как значение this. - person gsnedders; 10.03.2011
comment
@gsnedders, я не понимаю, что ты имеешь в виду. Хотите объяснить? - person David Tang; 10.03.2011

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

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

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

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

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

person Thai    schedule 09.03.2011

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

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

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

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

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

  1. Если код функции является строгим, задайте для ThisBinding значение thisArg.
  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. Выполните создание экземпляра привязки объявления, используя код кода функции и список аргументов, как описано в 10.5.

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

  1. сохраните его в локальной переменной в родительской области, например var self = this
  2. введите его с помощью вызова/применения, как код, который вы указали в своем вопросе.
person Martin Jespersen    schedule 09.03.2011