Please explain why, after assigning var f = obj1.f context of the call is lost and undefined is displayed?

 var obj1 = { x: 3, f: function() { return (this.x); } }; alert(obj1.f()); var f = obj1.f; alert(f()); 

  • 3
    The counter question, why did you decide that the context of the call should be preserved? - Dmitriy Simushev
  • five
    Because functions in javascript (as opposed to some other languages) exist by themselves, not bound to an object. In the first case, you call a function as an object method. In the second case, you get the function from the object, and then call it by itself. ru.wikipedia.org/wiki/… - Duck Learns to Take Cover
  • five
    Colleagues, the question is valid, maybe someone will give a detailed answer? It would be useful to those who are not special in JS (for example, me). - VladD
  • 2
    @VladD is a valid question, but the answer to it is in every first (well, maybe every second) textbook on JS. - Alexey Ten
  • five
    @AlexeyTen, 80 percent of js questions that appear here (and on other sites) are in every second js tutorial. And still will appear. Do not answer them chtoli? - Duck Learns to Take Cover

5 answers 5

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 normal function, in most cases the value of this will be a global object (for the browser 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(); 

Callback functions are usually called this way, which is why the value of this in them seems unexpected.


Method call

Method is a function located in the 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 value of this is the object in which the function is located, actually the value in front of the dot character.


Constructor call

The function can be called as a constructor. To do this, you need to use 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 value of this refers to this created object.

Feature: when using inheritance and classes from ES2015, accessing this before calling super depending on the browser will cause an exception about trying to access an undeclared / uninitialized variable.

 class A {} class B extends A { constructor(){ console.log(this); } } var b = new B(); 


Call using call and apply

When using the call and apply functions, you can set this value directly by passing it to 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 , these functions call callbacks passed to various functions, for example: each , map , on, and others. In this case, the current element of the collection or the html element is set as this .


Call as callbacks in array processing functions

Some built-in functions for an object of type Array allow you to directly specify the value of this for the transferred 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?

Declaration of a function or functional expression

Normal function declaration:

 function A(){} var a = function (){}; 

in a normal declaration, the value of this is determined when called in the ways described above.


Creating a function with bind

The bind function returns a new bound function. The value of this inside the created function is always the one that was passed when bind called.

An important feature: when using an anchored function as a constructor, the value of this will still indicate the object being created, as described above.

An important feature: when passing null and undefined values ​​as the this parameter, this parameter will be ignored and this will be set to the global object.

An important feature: the value of this for the created function cannot be redefined 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 appeared in ES2015 and, when created, are bound to the current value of this .

After creation, the value of this cannot be changed using the methods specified above.

In addition, the pointer function cannot be used as a constructor.

 function A(){ this.t = (place)=>console.log(place,this); } var a = new A() at('method:'); var tt = at; tt('free function execute:'); tt.call({o:'object'},'using call function'); new tt('constructor'); 


based on the answers:
- How does the “this” keyword work?
- How does “this” keyword work within a JavaScript object literal?

  • Then you were not lazy yet: = :) (+) - Alexandr_TT
  • one
    @Alexandr_TT, then there was still no question that could be referred to as a duplicate :) - Grundy

In short: in the first case, you call a function as a method of an object, in the second, you take the function by itself.

More verbose:
Functions in javascript, unlike some other popular languages, are so-called first-class objects . That is, they exist and make sense by themselves, without being tied to an object.

However, sometimes there is a natural desire to call a function as a method of an object. This means that functions need access to the object, by which method they want to make it, in order to use the properties of this object for example. But the function is by itself, that is, it can be called as a method of different objects, what to do? For this purpose the keyword this was invented. This can be understood as an object whose method this function is considered to be at this particular call.

Calling a function immediately through the point myObject.myFunction() is just a shortened way of setting this right away, a sort of sugar. When you call through a point, actually the following happens:

 var func = myObject.myFunction; //Получаем функцию-свойство объекта myObject func.call(myObject); // Вызываем эту функцию с нужным контекстом. 

To create a function with an associated context, for example, to pass to a handler, usually bind is used, for example:

 var func = myObject.myFunction.bind(myObject); 

    The function is called in the context of the object NOT because it is created inside the object. It is called in the context of the object, because it is called as the obj.func () method

    When a function is called as a method, the this identifier is automatically set to the object of this method.

    The same function can be called as methods of different objects.

     function foo() { blah blah } x = {}; x.foo=foo; x.foo() //тут this будет установлен на объект х x2 = {}; x2.foo=foo; x2.foo() //тут this будет установлен на объект х2 foo(); //тут this не будет установлен 

    The same if the function is initially created inside the object. It has no value. What matters is how the function is called.

      In addition to other answers.

      If you write in TypeScript , you can use the following decorator:

       function bound(target, propertyKey: PropertyKey, descriptor: PropertyDescriptor): PropertyDescriptor { var value = descriptor.value; return { configurable: descriptor.configurable, enumerable: descriptor.enumerable, get() { return value.bind(this); } } } 

      When the decorators appear in Javascript, you can write it there. When using Babel, you can do this in Javascript:

       function bound(target, propertyKey, descriptor) { var value = descriptor.value; return { configurable: descriptor.configurable, enumerable: descriptor.enumerable, get() { return value.bind(this); } } } 

      Using:

       class Foo { private readonly _baz; constructor(baz) { this._baz = baz; } @bound bar() { console.log(this._baz); } } var bar = new Foo(42).bar; bar(); // 42 

      If it is important that the successive calls to the property produce the same values ​​(for example, to avoid redundant renders in React), you will have to write a little more complicated code:

       var bfmc = Symbol("boundFunctionsMemoizedCache"); function bound(target, propertyKey: PropertyKey, descriptor: PropertyDescriptor): PropertyDescriptor { return { enumerable: descriptor.enumerable, get() { if (!this.hasOwnProperty(bfmc)) this[bfmc] = {}; if (this[bfmc].hasOwnProperty(propertyKey)) return this[bfmc][propertyKey]; return this[bfmc][propertyKey] = descriptor.value.bind(this); } } } 

      In principle, you can write a little easier (for example, create a separate symbol for each call bound or even redefine the propertyKey property) - but I'm not sure that such code can be properly optimized and will not generate a lot of hidden classes where it is not necessary. I will be glad to hear comments on this issue from someone who has already encountered Javascript optimizations for specific browsers.


      Comment. This answer shows the outdated old version of decorators, which will never be included in the standard. The new version is different, maybe I will update the answer when it is released.

      • var a = new Foo(7); console.log(a.bar === a.bar); - will be false. Can it be improved to be true? - Qwertiy
      • In the reactor, the PureComponent will be recalculated due to such changes, and this is bad. And in general, well, it’s logical that the link to the same function should be returned, and not to create a Bind clone on each call - all of a sudden it is called up in my cycle 1,000,000 times. - Qwertiy
      • Many thanks for the option - Vasya Shmarovoz
      • @Qwertiy remark is accepted. Finished the answer. - Pavel Mayorov
      • one
        @VasyaShmarovoz pay attention to the supplement - Pavel Mayorov

      When you create an object - you essentially create its context, this inside refers to the context of the object. After assigning this function to an ordinary variable - you yourself are tearing the function out of its context, thus the binding of this inside this function is lost, by this now is meant the object window. Ie, referring to this.x now actually you are accessing window.x which is undefined.

      The operation of assigning a function tied to an object, an external variable is not quite logical, the function cannot “remember” that it was once in an object, therefore it should use its context to search for attributes