Can you bind 'this' in an arrow function?

93,743

Solution 1

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

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

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

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

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.

Share:
93,743

Related videos on Youtube

Nebula
Author by

Nebula

Updated on March 21, 2022

Comments

  • Nebula
    Nebula over 2 years

    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.

    • loganfsmyth
      loganfsmyth over 8 years
      The whole point of arrow functions is that they use the this of their parent scope.
  • a better oliver
    a better oliver over 8 years
    "since the this is already binded" - In regular functions this is bound too. The point is that in arrow functions it has no local binding.
  • Marco Faustinelli
    Marco Faustinelli about 7 years
    Arrow functions were created first of all to provide a cleaner and faster syntax. Think lambda-calculus. Too bad the OO-zealots that pester the life of functional JS programmers grabbed the opportunity to take away the freedom to specify the invocation context.
  • Nebula
    Nebula over 6 years
    Is there a way to detect or use whatever object the (arrow) function is bound to, without referencing this (which is, of course, defined lexically)?
  • cvazac
    cvazac over 6 years
    Use an argument for context: ((context) => { someOtherFunction.apply(context) }).bind(willBeIgnored, context)()
  • Prithvi Raj Vuppalapati
    Prithvi Raj Vuppalapati about 6 years
    // 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();
  • Methodician
    Methodician over 5 years
    What's interesting here is to try this and then try it again replacing foo.method('bar', () => { console.log(this.test); }); with foo.method('bar', function () { console.log(this.test); }); - the first version logs "attached to the module" and the second logs "attached to the an object" - I really prefer the more stable treatment of "this" using arrow functions. You can still achieve the other effects using different patterns and the results are more readable and predictable IMO.
  • Eric Haynes
    Eric Haynes about 5 years
    Using this isn't functional. lambdas should be arguments => output. If you need some external context, pass it in. The very existence of this is what facilitated all of the shoehorning of OO patterns into the language. You would never have heard the term "javascript class" without it.
  • Stijn de Witt
    Stijn de Witt over 4 years
    You can rebind arrow functions. Just not this.
  • Nebula
    Nebula over 4 years
    function myFunc is behaviorally different in ways besides being bindable; a closer match would be const myFunc = function() {...}. I'm also curious what you mean by using eval, since that's an approach I don't think any answers have shared here before - it'd be interesting to see how that's done, and then read why it's so strongly discouraged.
  • Silviu Burcea
    Silviu Burcea over 3 years
    Here is one use case for rebinding: describe("Test suite", () => { before(function () { if (conditionIsNotMet) this.skip(); // skip the suite } }); If you change that function to arrow function, this.skip is lost.