Ответ Эрика дает вам разумный пример того, как делать то, что вы хотите сделать, но на самом деле не разбирается, почему.
В JavaScript this
полностью устанавливается как функция вызывается ( на данный момент ; подробности см. Ниже под сгибом), а не , где функция определен , как и в некоторых других языках, имеющих такое же ключевое слово (Java, C ++, C #, ...).
Вы, кодер, определяете, каким будет this
каждый раз, когда вы вызываете функцию. Есть два основных способа: вызвать функцию через свойство объекта (в том же выражении) или явно использовать встроенные в функцию функции call
и apply
.
через свойство объекта
Использование свойства объекта:
obj.foo(); // or
obj["foo"](); // both work
Это делает две совершенно разные вещи, но которые совместно устанавливают значение this
: во-первых, ссылка на функцию определяется путем поиска свойства foo
объекта obj
. Затем функция вызывается. Поскольку вы вызывали его как часть того же общего выражения, извлекающего значение свойства, механизм JavaScript установит this
в obj
в вызове.
Таким образом, в вашем примере test.parseText.load()
в вызове load
this
будет parseText
, а не test
, потому что это объект, на котором был найден load
.
Обратите внимание, что настройка- this
-via-property-lookup работает только тогда, когда они выполняются одновременно. Это не работает:
var f = obj.foo;
f(); // `this` will not be `obj` within the call
Это не работает, потому что они не были сделаны одновременно. Поиск свойства и вызов функции были разделены.
Использование call
или apply
Второй способ установки this
является более явным: все функции имеют свойства call
и apply
, которые сами являются ссылками на функции, которые вызывают функцию, используя предоставленную вами информацию. В обоих случаях первый аргумент - это объект, который будет использоваться как this
во время вызова. Поэтому, если мы хотим исправить приведенный выше пример, который не работает, мы можем сделать это:
var f = obj.foo;
f.call(obj); // `this` will be `obj` within the call
f.apply(obj); // same
Единственная разница между call
и apply
заключается в том, как вы задаете аргументы функции. С call
вы предоставляете их как дополнительные дискретные аргументы функции; с apply
вы передаете массив аргументов.
Так что все они делают одно и то же:
// 1 - Directly via property
obj.foo("a", "b", "c");
// 2 - Using `call`
f = obj.foo;
f.call(obj, "a", "b", "c");
// 3 - Using `apply`
f = obj.foo;
f.apply(obj, ["a", "b", "c"]); // Note the `[ ... ]`, one array with three elements
Вы можете увидеть, как call
и apply
могут работать с вашей существующей структурой:
test.parseText.load.call(test.parseText);
Это вызывает test.parseText.load
, делая this
= test.parseText
внутри звонка.
Что Эрик сделал в своем ответе, так это использовал закрытие, чтобы вам было проще звонить parseText
с ожидаемым значением this
.
Дальнейшее чтение (раскрытие: из моего блога):
Наверху я сказал:
В JavaScript this
полностью устанавливается как функция вызывается
( на данный момент ...
Причина, по которой я сказал «пока», заключается в том, что в ES6 JavaScript получает «функции стрелок», и в отличие от других функций, значение this
внутри функции стрелок задается там, где они созданы , не как они называются: они получают this
из контекста, где вы их создаете.
Предположим, вы писали код в объектном методе и хотели использовать другой метод объекта для, я не знаю, вывода информации из массива (да, это надумано). В ES5 вы, вероятно, сделали бы это:
this.output("Entries:");
theArray.forEach(function(entry, index) {
this.output(index + ": " + entry);
}, this);
// ^------- tells `forEach` what to use as `this` during the callback
Если вы пропустите аргумент, у вас будет ошибка:
this.output("Entries:");
theArray.forEach(function(entry, index) {
this.output(index + ": " + entry); // <== Bug, `this` is either
// `undefined` (strict) or
// the global object (loose)
});
Но поскольку функции-стрелки наследуют this
от того места, где они были созданы, а не получают его в зависимости от того, как они вызваны, версия функции-стрелки, для которой не требуется второй аргумент:
this.output("Entries:");
theArray.forEach((entry, index) => {
this.output(index + ": " + entry);
});