Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happens when you bind 'this' on an Ember function?

Tags:

javascript

I'm trying to better understand this Firebase authenticator for Ember SimpleAuth:

import Ember from 'ember';


export default Ember.Controller.extend({


actions: {
    login: function() {
        this.get('session').authenticate('authenticator:firebase', {
            'email': this.get('email'),
            'password': this.get('password')
        }).then(function() {
            this.transitionToRoute('index');
        }.bind(this));
    },
    logout: function() {
        this.get('session').invalidate().then(function() {
            this.transitionToRoute('login');
        }.bind(this));
    }
}
});

Would someone please explain what ".bind(this)" is doing and how exactly bind is working in this particular instance?

Edit: After a little reflection and research, here is my proposed explanation of what may be happening:

The ".then" section of the code does not have access to the original context of "this". The ".bind(this)" sets the value of "this" (which in this case is the current controller object) to the "this" inside the ".then" function.

This can be demonstrated by the fact that if the ".bind(this)" section is removed, the "transitionTo" section of the code does not work.

On the other hand, if we write the code as follows, we don't need to use ".bind(this)":

import Ember from 'ember';


export default Ember.Controller.extend({


actions: {
    login: function() {
    var _this = this;
        this.get('session').authenticate('authenticator:firebase', {
            'email': this.get('email'),
            'password': this.get('password')
        }).then(function() {
            _this.transitionToRoute('index');
        });
    },
    logout: function() {
      var _this = this; 
        this.get('session').invalidate().then(function() {
            _this.transitionToRoute('login');
        });
    }
}


});

Thoughts?

like image 395
learningMachine Avatar asked Jun 28 '15 13:06

learningMachine


1 Answers

What happens when you bind 'this' on an Ember function?

In your example, .bind() is not used on Ember functions. It is used on usual anonymous functions (callbacks). Thus, your question has nothing to do with Ember.

By a callback I mean an anonymous function passed as an argument rather than assigned to a property of an object.

Such a function will be bound to window, i. e. this within the function would return window.

A traditional approach of accessing the outer scope is assigning this to a variable in an outer scope, then accessing the variable in the inner scope:

var _this = this;

someMethod(function() {
  console.log(this);  // => window
  console.log(_this); // => Outer scope
});

This approach is good when you need to access both inner and outer scope. But there's nothing useful in the inner scope, so we can write it shorter:

someMethod(function() {
  console.log(this); // Outer scope
}.bind(this));

The .bind() method is executed in the outer scope on the anon function. It binds the function to the outer scope. Thus, the inner scope of the function will be the same as the the outer scope, and you can use this as usual, as if the scope didn't change.

In CoffeeScript, you can use the fat arrow to stay in the outer scope:

_this = this

someMethod ->
  console.log this  # winodw
  console.log _this # Outer scope
someMethod =>
  console.log this     # Outer scope
  console.log ` this ` # You can still access window like ` this `, pun intended

In ES6 you can use the fat arrow too:

foo( () => {
  console.log(this);
});

Mind that though like in CoffeeScript the fat arrow maintains the outer scope, it means a different thing! In ES6 the fat arrow creates a fake function that is unable to have its own scope.

This is important because some libraries communicate with a callback by applying the callback to a certain scope and expect you to do this.something() on it. It won't work with ES6 fat arrow (well, it could technically work with Babel because Babel converts ES6 fat arrows into traditional functions, but you should not rely on that).

For more info on .bind(), see Function.prototype.bind() on MDN.

like image 72
Andrey Mikhaylov - lolmaus Avatar answered Nov 03 '22 18:11

Andrey Mikhaylov - lolmaus