Ответ 1
Это довольно просто, как только вы узнаете, как методы работают в javascript за кулисами.
toUpperCase
- метод. Это функция, которая работает с определенным объектом... обычно с помощью переменной this
.
Javascript - это прототип языка... означает, что функции, связанные с объектами, являются просто функциями и могут быть скопированы. Существует некоторая работа за кулисами, которая гарантирует, что this
устанавливается правильно, когда вы вызываете метод, но эта работа происходит только тогда, когда вы называете ее как метод... как в форме obj.method()
.
Другими словами: ''.toUpperCase()
гарантирует, что this
устанавливается в строку ''
, когда вы вызываете его.
Когда вы называете это как toUpperCase()
this
не настроено ни на что конкретно (разные среды в этом случае делают разные вещи с this
)
Что ваш код может быть переписан следующим образом:
var function_to_call;
if (true) {
function_to_call = ''.toLowerCase;
} else {
function_to_call = ''.toUpperCase;
}
function_to_call();
Поскольку ваш вызов функции: function_to_call()
не находится в синтаксисе object.method()
, вещь, которая устанавливает this
на правильный объект, не выполняется, а ваш вызов функции выполняется с this
, не установленным на то, что вы хотите.
Как указывали другие люди, вы можете использовать func.call(thing_to_make_this)
или func.apply()
, чтобы прикрепить к нему правильную вещь.
Я считаю гораздо более полезным использовать .bind()
- который, по моему мнению, крайне недоиспользуется. function_name.bind(this_object)
дает вам новую функцию, которая всегда будет привязана к this
:
// assuming function_to_call is set
function_that_works = function_to_call.bind(my_object)
function_that_works(); // equivalent to my_object.function_to_call()
и это означает, что вы можете передать функцию, возвращаемую из bind()
, как и обычную функцию, и она будет работать на нужном объекте. Это особенно полезно при обратных вызовах, поскольку вы можете создать анонимную функцию, связанную с объектом, в котором он был создан:
// this won't work because when this runs, 'this' doesn't mean what you think
setTimeout(function() { this.display_message('success'); }, 2000);
// this will work, because we have given setTimeout a pre-bound function.
setTimeout(function() { this.display_message('success'); }.bind(this), 2000);
TL; DR: вы не можете вызвать метод как функцию и ожидать, что он будет работать, потому что он не знает, что должно быть this
. Если вы хотите использовать эту функцию, вы должны использовать .call()
, .apply()
или .bind()
, чтобы убедиться, что this
правильно настроен к моменту выполнения функции.
Надеюсь, что это поможет.