Question:
Can you please explain why after assigning var f = obj1.f
the call context is lost and undefined
is displayed?
var obj1 = {
x: 3,
f: function() {
return (this.x);
}
};
alert(obj1.f());
var f = obj1.f;
alert(f());
Answer:
The value of this
inside a function depends on how the function is called and how the function is created.
How is it called?
You can call a function in the following ways:
Function call
If there is a regular function, in most cases the value of this
will be the global object (for the browser's window ). When using "strict mode" – undefined .
var f = function (){
console.log('common:',this.toString());
};
f();
var fStrict = function (){
"use strict";
console.log('strict:', this);
};
fStrict();
This is usually how callback functions are called, which is why the this value in them seems unexpected.
For example, when passing a function to .addEventListener
, the this value will be the element to which the handler is added.
Method call
A method is a function in an object.
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();
When a function is called as a method, the this value is the object in which the function resides, in fact the value before the dot character.
Constructor call
A function can be called as a constructor by using the new
operator before the call: new Foo()
function Foo(name){
this.name = name;
}
var foo = new Foo('foo');
console.log(foo);
When a function is called as a constructor, a new object is created, and the this value refers to this created object.
Feature: when using inheritance and classes from ES2015 , accessing this before calling super , depending on the browser, will throw an exception about trying to access an undeclared / uninitialized variable.
class A {}
class B extends A {
constructor(){
console.log(this);
}
}
var b = new B();
Calling with the call
and apply
methods
When using the call
and apply
functions, you can set the this value directly by passing it as the first parameter.
var f = function (){
console.log('common:',this);
};
f.call({o:'object'});
var fStrict = function (){
"use strict";
console.log('strict:', this);
};
fStrict.apply({o:'object'});
In libraries like jQuery , callbacks passed to various functions, such as each , map , on , and others, are called using these functions. In this case, the current element of the collection, or an html element, is set as this.
Calling as Callbacks in Array Processing Functions
Some built-in functions for an Array
object also allow you to directly specify the this value for the passed callback:
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);
How is it created?
Declaring a function or function expression
Normal function declaration:
function A(){}
var a = function (){};
in a normal declaration, the this value is determined when called in the ways described above.
Creating a function with bind
The bind
function returns a new bound function. The this value inside the created function is always the one passed when bind
was called.
An important feature: when using a bound function as a constructor, the this value will still point to the object being created, as described above.
An important feature: in NOT strict mode , when passing null
and undefined
as the this parameter, this parameter will be ignored and this will be set to the global object.
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)();
An important feature: the this value of the created function cannot be overridden using the call
and apply
functions described above.
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();
Arrow functions
Arrow functions were introduced in ES2015 and are bound to the current value of this when they are created.
Once created, the this value cannot be changed in the ways above.
Also, an arrow function cannot be used as a constructor.
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?