0

Why is this undefined in example one, but defined in example two? I thought the arrow notation would allow the binding to be on higher scope, in this case the object literal.

Example 1:

var runApp = {
    init: () => {
         console.log(this); //this is an empty object.  
         this.run() //will crash here, run not a function of this.
    },
    run: () => { 
         console.log("It's running!");
    }
};

// Now we call init
runApp.init();

Example 2:

var runApp = {
    init: function(){
         console.log(this);   
         this.run()
    },
    run: function() { 
         console.log("It's running!");
    }
};

// Now we call init
runApp.init();
Matt Kuhns
  • 1,162
  • 1
  • 10
  • 23
  • 1
    An arrow function expression is a syntactically compact alternative to a regular function expression, although without its own bindings to the this, arguments, super, or new.target keywords: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions – Tom O. Aug 23 '19 at 17:08
  • The articles referenced in the answers are helpful. I think an additional remark is that object literals do not create their own scope, only functions do. – Matt Kuhns Aug 23 '19 at 17:28

4 Answers4

1

It's because you are using an arrow function. The arrow function will always maintain the context of where it was syntactically defined. In your example this will most likely be the window or global object, which does not have the init function defined.

Non arrow functions will determine the context dynamically based on object they are being referenced by. Unless the context has been explicitly set trough .bind earlier, or trough .apply or .call at the call site.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this

Willem D'Haeseleer
  • 17,802
  • 6
  • 58
  • 92
1

No, arrow functions do not add a higher scope. Only regular functions do. Arrow functions are special because they bring in the scope before it. The get the scope of where the function was defined.

This is useful in some places, like constructors. You don't have to define a variable as this to use in functions. But in other cases when you need to get the new scope, you need to use the regular functions. It's why you can't make constructors with arrow functions.

Here is documentation of arrow functions (MDN).

Craftingexpert1
  • 380
  • 1
  • 10
1

In the first example, this does not refer to the object named runApp, but the context in which runApp.init() was executed, hence the term 'execution context'. For example:

var orange = "orange";

var runApp = {
    init: () => {
         runApp.run() // This will work

         this.run() // This will not work

         console.log(this.orange); // Prints orange
    },
    run: () => {
        console.log("I am running!");
    }
};

// Now we call init
runApp.init();

You will notice in the above code that this.orange is defined, while this.run() is undefined. Note: This is true for the browser, but not Node.js.

You can read more about this here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this

Adam Patterson
  • 908
  • 7
  • 13
  • Yes, I tried in Node and it prints undefined. Is that because the browser defines global scope (window, I believe)? Whereas, Node has no global scope. – Matt Kuhns Aug 23 '19 at 17:42
  • I think it is described here: https://stackoverflow.com/questions/43627622/what-is-the-global-object-in-nodejs – Matt Kuhns Aug 23 '19 at 17:44
  • Yes basically. More specifically, Node.js does have a global scope, but the code in the module does not belong to it. Anything that is exported by the module will be accessible globally though. For example, if you were to add the line `module.exports.orange = 'orange';` Then `this.orange` should print orange. – Adam Patterson Aug 23 '19 at 17:50
0

arrow functions inherit this from the context in which they're created.

Regular functions context is determined dynamically based on object to which they are called before the Dot notation. e.g myObj.init() so the context of init will be myObj and this will be referenced to myObj. Unless the context has been explicitly set .bind, .apply or .call at the call site to change the context of calling.

However the above fat arrow method can be wrapped with regular function to work around:

var orange = "orange";
var runApp = {
    a : 'object???',
    init : function() {
        return (() => {
            console.log(this.a)
        })();
    },
    run: () => {
        console.log("I am running!");
    }
};


// Now we call init
runApp.init();

khizer
  • 444
  • 5
  • 8