this
отличается в JavaScript от других языков, таких как C ++ или Java.Значение this
в вашем первом примере всегда будет глобальным объектом (window
в браузерах).this
во втором примере - это объект jsn
для первого предупреждения и window
для второго.Это потому, что this
определяется полностью тем, как вызывается функция, а не тем, где она определена.
Если вы не делаете ничего особенного при вызове функции, this
глобальный объект.Когда вы вызываете функцию через свойство объекта (jsn.func()
), this
устанавливается для объекта, из которого получено свойство.(Но не поймите неверное впечатление, func
никоим образом не привязан к jsn
; JavaScript не имеет методов , только функции; детали .) f1
затем возвращает функцию, которая вызывается в финале alert
;поскольку этот вызов не осуществляется через свойство объекта, для глобального объекта устанавливается this
.
Некоторые примеры:
// Simple function
function foo() {
alert(this === window);
}
foo(); // true, within the call, `this` === `window`
// Object example, and twist at the end
var obj = {
func: function() {
alert(this === obj);
},
};
obj.func(); // true, within the call, `this` === `obj`
obj["func"](); // true, within the call, `this` === `obj`
var f = obj.func; // Not calling it, just getting a reference to the function
f(); // false, within the call `this` !== `obj` (`this` === `window`)
// Creating functions on the fly, returning them, and how that has
// nothing whatsoever to do with how `this` gets set:
var obj = {
func: function() {
return function() {
alert("I'm a generated function");
alert(this === obj);
};
}
};
obj.func()(); // alerts the "I'm a generated function", then false; `this` !== `obj`
obj.bar = obj.func();
obj.bar(); // alerts the "I'm a generated function", then true; `this` === `obj`
Существует второй способ управления тем, что находится внутри this
функция: используйте функции JavaScript .call
или .apply
:
var obj = {
func: function() {
alert(this === obj);
}
};
function foo(a, b) {
alert(this === obj); // Yes, really obj; see below
alert(a);
alert(b);
}
foo(1, 2); // alerts false (`this` !== `obj`), then 1, then 2
obj.func(); // alerts true, `this` === `obj`
foo.call(obj, 3, 4); // alerts true (`this` === `obj`), then 3, then 4
foo.apply(obj, [5, 6]); // alerts true (`this` === `obj`), then 5, then 6
Как видите, первый аргумент call
или apply
- это объект, который нужно сделать this
в вызове функции.Единственная разница между call
и apply
заключается в том, как вы указываете аргументы для передачи в целевую функцию: при call
вы просто предоставляете их после первого аргумента;с помощью apply вы предоставляете их в виде массива.
И, наконец, есть третий способ: ключевое слово new
.JavaScript имеет концепцию функций конструктора .Назначение функции конструктора - создавать экземпляры объектов, инициализированных определенным образом.Вот пример:
function Foo(b) {
this.bar = b;
}
var f = new Foo();
Технически, любая функция может использоваться в качестве функции конструктора.Соглашение состоит в том, чтобы предоставлять функции, предназначенные для использования с new
именами, начинающимися с заглавной буквы, просто для подтверждения того, что мы вызываем их особым образом.
Вызов функции через new
создает новый объектэкземпляр и делает этот объект значением this
в вызове функции.Итак,
function Foo(b) {
alert(this === window);
}
var f = new Foo(); // alerts false, `this` !== `window` (it points to the new object created for the call)
var f = Foo(); // alerts true, `this` === `window` because we didn't use `new`
Как видите, важно правильно вызывать функцию.Если он предназначен для использования с new
, позвоните по номеру new
;если это не так, не надо.
(new
делает больше, чем просто создает пустой объект; у созданного объекта есть некоторые другие аспекты, настроенные определенным образом. Я не буду вдаваться в подробности здесь, но я не хотел оставлять у вас впечатление, что все это было создание нового экземпляра объекта.)