Search code examples
javascriptecmascript-6ecmascript-5

New object instance copy method has undefined context. (sorry for misleading title)


I am curios why this ES6 code outputs undefined:

class Test {
  constructor(name) {
    this.name = name;
  }
  
  log() {
    console.log(this);
  }

}


const t = new Test('asd');
const asd = t.log;
asd();

but this ES5 code outputs window.

 function Test(name) {
   this.name = name;
 }
 
 Test.prototype.log = function() {
   console.log(this)
 }
 
 const t = new Test('newer test');
 const asd = t.log;
 asd();

Techincally with something is invoked in the globar score it has window.thatSomething in front but apparently if thatSomething is a class there is no window.


Solution

  • This is because the class by default makes your code use strict mode. Normally, the value of this will be assigned to the global object (window) if not determined but in strict mode, it's set to undefined to prevent accidental problems like using properties of the global object:

    function sayName() {
      console.log("Hello, my name is " + this.name + "!");
    }
    
    function sayNameStrict() {
      "use strict";
      console.log("Hello, my name is " + this.name + "!");
    }
    
    let obj = {
      name: "Fred",
      sayName: sayName,
      sayNameStrict: sayNameStrict
    }
    
    obj.sayName(); //this = obj, this.name = "Fred
    
    sayName(); //this = window, this.name = window.name
    
    obj.sayNameStrict(); //this = obj, this.name = "Fred
    
    sayNameStrict(); //this = undefined, this.name = TypeError

    So, if you execute your second piece of code in strict mode, you'll get the same outcome as the ES6 class:

    "use strict";
    
    function Test(name) {
      this.name = name;
    }
    
    Test.prototype.log = function() {
      console.log(this)
    }
    
    const t = new Test('newer test');
    const asd = t.log;
    asd();