Can you bind 'this' in an arrow function?

JavascriptFunctionEcmascript 6

Javascript Problem Overview


I've been experimenting with ES6 for a while now, and I've just come to a slight problem.

I really like using arrow functions, and whenever I can, I use them.

However, it would appear that you can't bind them!

Here is the function:

var f = () => console.log(this);

Here is the object I want to bind the function to:

var o = {'a': 42};

And here is how I would bind f to o:

var fBound = f.bind(o);

And then I can just call fBound:

fBound();

Which will output this (the o object):

{'a': 42}

Cool! Lovely! Except that it doesn't work. Instead of outputting the o object, it outputs the window object.

So I'd like to know: can you bind arrow functions? (And if so, how?)


I've tested the code above in Google Chrome 48 and Firefox 43, and the result is the same.

Javascript Solutions


Solution 1 - Javascript

You cannot rebind this in an arrow function. It will always be defined as the context in which it was defined. If you require this to be meaningful you should use a normal function.

From the ECMAScript 2015 Spec:

> Any reference to arguments, super, this, or new.target within an ArrowFunction must resolve to a binding in a lexically enclosing environment. Typically this will be the Function Environment of an immediately enclosing function.

Solution 2 - Javascript

To be complete, you can re-bind arrow functions, you just can't change the meaning of this.

bind still has value for function arguments:

((a, b, c) => {
  console.info(a, b, c) // 1, 2, 3
}).bind(undefined, 1, 2, 3)()

Try it here: http://jsbin.com/motihanopi/edit?js,console

Solution 3 - Javascript

From the MDN:

> An arrow function expression has a shorter syntax compared to function expressions and lexically binds the this value (does not bind its own this, arguments, super, or new.target). Arrow functions are always anonymous.

This means you cannot bind a value to this like you want.

Solution 4 - Javascript

description: Stijn de Witt

You cannot use bind to change the value of this inside an arrow function. However, you can create a new regular function that does the same thing as the old arrow function and then use call or bind to re-bind this as usual.

We use an eval call here to recreate the arrow function you pass in as a normal function and then use call to invoke it with a different this:

code: me

const func = v => console.log(this);
const obj = {value: 10};

function arrowBindOld(context, fn) {
  let arrowFn;
  (function() {
    arrowFn = eval(fn.toString());
    arrowFn();
  }).call(context);
}
arrowBindOld(obj, func);

update

const f = v => console.log(this, v);
const o = {value: 10};

/* new */
function arrowBind(context, fn) {
  const arrowFnString = fn.toString();
  return (function() {
    return eval(arrowFnString);
  }).call(context);
}
const fBound = arrowBind(o, f);
fBound(10);

/* use prototype */
Function.prototype.arrowBind = function(context) {
  const arrowFnString = this.toString();
  return (function() {
    return eval(arrowFnString);
  }).call(context);
}
const fBoundProto = f.arrowBind(o);
fBoundProto(20);

Solution 5 - Javascript

For years, js developers struggled with context binding, asked why this changed in javascript, so much confusion over the years due to context binding and the difference between the meaning of this in javascript and this in most of the other OOP languages.

All this leads me to ask, why, why! why would you wan't to rebind an arrow function! Those where created specially to solve all this issues and confusions and avoid having to use bind or call or whatever other way to preserve the scope of the function.

TL;DR

No, you cannot rebind arrow functions.

Solution 6 - Javascript

I asked the same question a couple days ago.

You cannot bind a value since the this is already bound.

https://stackoverflow.com/questions/33284596/binding-different-this-scope-to-es6-function-operator?noredirect=1#comment54383518_33284596

Solution 7 - Javascript

Do ES6 Arrow Functions Really Solve “this” In JavaScript

The above link explains that arrow functions this doesn't change with bind, call, apply functions.

It is explained with a very nice example.

run this in node v4 to see the "expected" behavior,

this.test = "attached to the module";
var foo = { test: "attached to an object" };
foo.method = function(name, cb){ 
    // bind the value of "this" on the method 
    // to try and force it to be what you want 
    this[name] = cb.bind(this); };
foo.method("bar", () => { console.log(this.test); });
foo.bar(); 

Solution 8 - Javascript

I think this is better solution

var f = (vm=this) => console.log(vm);

Solution 9 - Javascript

Maybe this example help to you :

let bob = {
   _name: "Bob",
   _friends: ["stackoverflow"],
   printFriends:(x)=> {
      x._friends.forEach((f)=> {
         console.log(x._name + " knows " + f);
      });
   }
}

bob.printFriends = (bob.printFriends).bind(null,bob);
bob.printFriends();

Solution 10 - Javascript

Short, You CANNOT bind arrow functions, but read on:

Imagine you have this arrow function below which prints this on the console:

const myFunc = ()=> console.log(this);

So the quick fix for this would be using normal function, so just change it to:

function myFunc() {console.log(this)};

Then you can bind it to any lexical environment using bind or call or apply:

const bindedFunc = myFunc.bind(this);

and call it in case of bind.

bindedFunc();

There are also ways to using eval() to do it, which strongly not recommended.

Solution 11 - Javascript

Normal bind:

tag.on("Initialized", function(tag) {
   nodeValueChanged(tag, currentNode)
}.bind(currentNode))

Arrow function bind:

tag.on("Initialized", (tag => { nodeValueChanged(tag, currentNode) }).bind(currentNode))

Solution 12 - Javascript

Arrow functions always have this based on its closest non-arrow function irrespective of where it is called. If there is no non-arrow parent it always refers to the global object.

Solution 13 - Javascript

While you are calling the arrow function using call/bind/apply it's doesn't point to the object which you are passing.

var obj = {a:1};
var  add=(b)=>{
return this.a + b;
// basically here this.a will be undefined as it's trying to find in one level up which is parents of this function that is window.
}

add.call(obj,2);

So that's why passing object doesn't work in arrow function.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFlorrieView Question on Stackoverflow
Solution 1 - JavascriptNick TomlinView Answer on Stackoverflow
Solution 2 - JavascriptcvazacView Answer on Stackoverflow
Solution 3 - JavascriptSterling ArcherView Answer on Stackoverflow
Solution 4 - JavascripttheNameView Answer on Stackoverflow
Solution 5 - JavascripttaxicalaView Answer on Stackoverflow
Solution 6 - Javascriptfos.alexView Answer on Stackoverflow
Solution 7 - JavascriptPrithvi Raj VuppalapatiView Answer on Stackoverflow
Solution 8 - JavascriptLokendra SinghView Answer on Stackoverflow
Solution 9 - JavascriptEhsanView Answer on Stackoverflow
Solution 10 - JavascriptAlirezaView Answer on Stackoverflow
Solution 11 - JavascriptBurak DalkıranView Answer on Stackoverflow
Solution 12 - JavascriptBhanu AyinalaView Answer on Stackoverflow
Solution 13 - JavascriptJitendra singhView Answer on Stackoverflow