Объясните, пожалуйста, почему после присвоения var f = obj1.f теряется контекст вызова и выводится undefined?
var obj1 = { x: 3, f: function() { return (this.x) } } alert(obj1.f()) var f = obj1.f alert(f())
Ответ Значение 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 в них кажется неожиданным. Например, при передаче функции в .addEventListener, значением 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()
Когда функция вызывается как метод, значением this является объект в котором находится функция, фактически значение перед символом точки.
Вызов конструктора Функцию можно вызывать в качестве конструктора, для этого перед вызовом нужно использовать оператор 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 для передаваемого коллбэка: Array.every Array.filter Array.find Array.findIndex Array.forEach Array.map Array.some
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')
на основе ответов: - How does the “this” keyword work? - How does “this” keyword work within a JavaScript object literal?