Вопрос:
Объясните, пожалуйста, почему после присвоенияvar f = obj1.f
теряется контекст вызова и выводитсяundefined
?
var obj1 = {
x: 3,
f: function() {
return (this.x);
}
};
alert(obj1.f());
var f = obj1.f;
alert(f());
Онлайн курс ReactJS в Черкассах | ReactWarriors
Ответ:
Значениеthis
внутри функции зависит от тогокак вызываетсяфункция икак созданафункция.
Вызвать функцию можно следующими способами:
Если есть обычная функция, в большинстве случаев значениемthis
будет глобальный объект (для браузераwindow). При использовании“strict mode”-undefined.
var f = function (){
console.log('common:',this.toString());
};
f();
var fStrict = function (){
"use strict";
console.log('strict:', this);
};
fStrict();
Обычно так вызываются функции обратного вызова(callback), вот почему значениеthisв них кажется неожиданным.
Метод - это функция находящаяся в объекте
var Obj = {toString:function(){ return "[object Obj]";}};
Obj.f = function (){
console.log('common:',this.toString());
};
Obj.f();
Obj.fStrict = function (){
"use strict";
console.log('strict:', this.toString());
};
Obj.fStrict();
Онлайн курс ReactJS в Черкассах | ReactWarriors
Функцию можно вызывать в качестве конструктора, для этого перед вызовом нужно использовать операторnew
:new Foo()
function Foo(name){
this.name = name;
}
var foo = new Foo('foo');
console.log(foo);
При вызове функции в качестве конструктора создается новый объект, и значениеthisссылается на это созданный объект.
Особенность:при использовании наследования иклассов из ES2015обращение кthisдо вызоваsuperв зависимости от браузера вызовет исключение о попытке обратиться к необъявленной/неинициализированной переменной.
class A {}
class B extends A {
constructor(){
console.log(this);
}
}
var b = new B();
call
иapply
При использовании функцийcall
иapply
можно задать значениеthisнапрямую, передав его первым параметром.
var f = function (){
console.log('common:',this);
};
f.call({o:'object'});
var fStrict = function (){
"use strict";
console.log('strict:', this);
};
fStrict.apply({o:'object'});
В библиотеках вродеjQueryс помощью этих функций вызываются коллбэки передаваемые в различные функции, например:each,map,onи другие. В качествеthisв этом случае устанавливается текущий элемент коллекции, либо html-элемент.
Некоторые встроенные функции для объекта типаArray
позволяют так же напрямую указать значениеthisдля передаваемого коллбэка:
var specialMap = {'b':'specialB','d':'specialD'}
var source= ['a','b','c','d','e'];
var mapped = source.map(function(el){
return this[el] || ('common-'+el);
},specialMap);
console.log('source:',source);
console.log('mapped:',mapped);
Обычное объявление функции:
function A(){}
var a = function (){};
при обычном объявлении значениеthisопределяется при вызове способами описанными выше.
bind
Функцияbind
возвращаетновую*привязаннуюфункцию. Значениеthisвнутри созданной функциивсегда*то, которое передали при вызовеbind
.
Важная особенность:при использовании привязанной функции в качестве конструктора, значениеthisвсе равно будет указывать на создаваемый объект, как описано выше.
Важная особенность:вНЕ strict modeпри передаче в качестве параметраthisзначенийnull
иundefined
- этот параметр будет проигнорирован иthisбудет установлен в глобальный объект.
function A(){console.log(typeof this,'is window', this === window);}
console.log('execute with null');
A.bind(null)();
console.log('execute with undefined');
A.bind(undefined)();
function A1(){'use strict'; console.log(typeof this, this);}
console.log('execute with null');
A1.bind(null)();
console.log('execute with undefined');
A1.bind(undefined)();
Важная особенность:значениеthisу созданной функциинельзяпереопределить используя функцииcall
иapply
описанные выше.
function A(){console.log(this);}
var B = A.bind({o:'object'});
console.log('execute binded');
B();
console.log('execute with call');
B.call({another: 'some new object'});
console.log('execute as constructor');
new B();
Стрелочные функции появились в ES2015 и при создании привязываются к текущему значениюthis.
После создания значениеthisнельзя поменять указанными выше способами.
Кроме того стрелочную функциюнельзяиспользовать в качестве конструктора.Источник
function A(){
this.t = (place)=>console.log(place,this);
}
var a = new A()
a.t('method:');
var tt = a.t;
tt('free function execute:');
tt.call({o:'object'},'using call function');
new tt('constructor');
Онлайн курс ReactJS в Черкассах | ReactWarriors