Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?












309















Canonical question If you find a question about issues after replacing a function declaration / expression with an arrow function, please close it as duplicate of this one.




Arrow functions in ES2015 provide a more concise syntax. Can I replace all my function declarations / expressions with arrow functions now? What do I have to look out for?



Examples:



Constructor function



function User(name) {
this.name = name;
}

// vs

const User = name => {
this.name = name;
};


Prototype methods



User.prototype.getName = function() {
return this.name;
};

// vs

User.prototype.getName = () => this.name;


Object (literal) methods



const obj = {
getName: function() {
// ...
}
};

// vs

const obj = {
getName: () => {
// ...
}
};


Callbacks



setTimeout(function() {
// ...
}, 500);

// vs

setTimeout(() => {
// ...
}, 500);


Variadic functions



function sum() {
let args = .slice.call(arguments);
// ...
}

// vs
const sum = (...args) => {
// ...
};









share|improve this question




















  • 3




    Similar questions about arrow functions have come up more and more with ES2015 becoming more popular. I didn't feel like there was a good canonical question/answer for this issue so I created this one. If you think that there already is a good one, please let me know and I will close this one as duplicate or delete it. Feel free to improve the examples or add new ones.
    – Felix Kling
    Dec 18 '15 at 17:59








  • 2




    What about JavaScript ecma6 change normal function to arrow function? Of course, a normal question can never be as good and generic as one specifically written to be a canonical.
    – Bergi
    Dec 18 '15 at 23:53
















309















Canonical question If you find a question about issues after replacing a function declaration / expression with an arrow function, please close it as duplicate of this one.




Arrow functions in ES2015 provide a more concise syntax. Can I replace all my function declarations / expressions with arrow functions now? What do I have to look out for?



Examples:



Constructor function



function User(name) {
this.name = name;
}

// vs

const User = name => {
this.name = name;
};


Prototype methods



User.prototype.getName = function() {
return this.name;
};

// vs

User.prototype.getName = () => this.name;


Object (literal) methods



const obj = {
getName: function() {
// ...
}
};

// vs

const obj = {
getName: () => {
// ...
}
};


Callbacks



setTimeout(function() {
// ...
}, 500);

// vs

setTimeout(() => {
// ...
}, 500);


Variadic functions



function sum() {
let args = .slice.call(arguments);
// ...
}

// vs
const sum = (...args) => {
// ...
};









share|improve this question




















  • 3




    Similar questions about arrow functions have come up more and more with ES2015 becoming more popular. I didn't feel like there was a good canonical question/answer for this issue so I created this one. If you think that there already is a good one, please let me know and I will close this one as duplicate or delete it. Feel free to improve the examples or add new ones.
    – Felix Kling
    Dec 18 '15 at 17:59








  • 2




    What about JavaScript ecma6 change normal function to arrow function? Of course, a normal question can never be as good and generic as one specifically written to be a canonical.
    – Bergi
    Dec 18 '15 at 23:53














309












309








309


195






Canonical question If you find a question about issues after replacing a function declaration / expression with an arrow function, please close it as duplicate of this one.




Arrow functions in ES2015 provide a more concise syntax. Can I replace all my function declarations / expressions with arrow functions now? What do I have to look out for?



Examples:



Constructor function



function User(name) {
this.name = name;
}

// vs

const User = name => {
this.name = name;
};


Prototype methods



User.prototype.getName = function() {
return this.name;
};

// vs

User.prototype.getName = () => this.name;


Object (literal) methods



const obj = {
getName: function() {
// ...
}
};

// vs

const obj = {
getName: () => {
// ...
}
};


Callbacks



setTimeout(function() {
// ...
}, 500);

// vs

setTimeout(() => {
// ...
}, 500);


Variadic functions



function sum() {
let args = .slice.call(arguments);
// ...
}

// vs
const sum = (...args) => {
// ...
};









share|improve this question
















Canonical question If you find a question about issues after replacing a function declaration / expression with an arrow function, please close it as duplicate of this one.




Arrow functions in ES2015 provide a more concise syntax. Can I replace all my function declarations / expressions with arrow functions now? What do I have to look out for?



Examples:



Constructor function



function User(name) {
this.name = name;
}

// vs

const User = name => {
this.name = name;
};


Prototype methods



User.prototype.getName = function() {
return this.name;
};

// vs

User.prototype.getName = () => this.name;


Object (literal) methods



const obj = {
getName: function() {
// ...
}
};

// vs

const obj = {
getName: () => {
// ...
}
};


Callbacks



setTimeout(function() {
// ...
}, 500);

// vs

setTimeout(() => {
// ...
}, 500);


Variadic functions



function sum() {
let args = .slice.call(arguments);
// ...
}

// vs
const sum = (...args) => {
// ...
};






javascript ecmascript-6 arrow-functions






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 5 '18 at 15:36

























asked Dec 18 '15 at 17:58









Felix Kling

545k126847906




545k126847906








  • 3




    Similar questions about arrow functions have come up more and more with ES2015 becoming more popular. I didn't feel like there was a good canonical question/answer for this issue so I created this one. If you think that there already is a good one, please let me know and I will close this one as duplicate or delete it. Feel free to improve the examples or add new ones.
    – Felix Kling
    Dec 18 '15 at 17:59








  • 2




    What about JavaScript ecma6 change normal function to arrow function? Of course, a normal question can never be as good and generic as one specifically written to be a canonical.
    – Bergi
    Dec 18 '15 at 23:53














  • 3




    Similar questions about arrow functions have come up more and more with ES2015 becoming more popular. I didn't feel like there was a good canonical question/answer for this issue so I created this one. If you think that there already is a good one, please let me know and I will close this one as duplicate or delete it. Feel free to improve the examples or add new ones.
    – Felix Kling
    Dec 18 '15 at 17:59








  • 2




    What about JavaScript ecma6 change normal function to arrow function? Of course, a normal question can never be as good and generic as one specifically written to be a canonical.
    – Bergi
    Dec 18 '15 at 23:53








3




3




Similar questions about arrow functions have come up more and more with ES2015 becoming more popular. I didn't feel like there was a good canonical question/answer for this issue so I created this one. If you think that there already is a good one, please let me know and I will close this one as duplicate or delete it. Feel free to improve the examples or add new ones.
– Felix Kling
Dec 18 '15 at 17:59






Similar questions about arrow functions have come up more and more with ES2015 becoming more popular. I didn't feel like there was a good canonical question/answer for this issue so I created this one. If you think that there already is a good one, please let me know and I will close this one as duplicate or delete it. Feel free to improve the examples or add new ones.
– Felix Kling
Dec 18 '15 at 17:59






2




2




What about JavaScript ecma6 change normal function to arrow function? Of course, a normal question can never be as good and generic as one specifically written to be a canonical.
– Bergi
Dec 18 '15 at 23:53




What about JavaScript ecma6 change normal function to arrow function? Of course, a normal question can never be as good and generic as one specifically written to be a canonical.
– Bergi
Dec 18 '15 at 23:53












2 Answers
2






active

oldest

votes


















471














tl;dr: No! Arrow functions and function declarations / expressions are not equivalent and cannot be replaced blindly.

If the function you want to replace does not use this, arguments and is not called with new, then yes.





As so often: it depends. Arrow functions have different behavior than function declarations / expressions, so lets have a look at the differences first:



1. Lexical this and arguments



Arrow functions don't have their own this or arguments binding. Instead, those identifiers are resolved in the lexical scope like any other variable. That means that inside an arrow function, this and arguments refer to the values of this and arguments in the environment the arrow function is defined in (i.e. "outside" the arrow function):






// Example using a function expression
function createObject() {
console.log('Inside `createObject`:', this.foo);
return {
foo: 42,
bar: function() {
console.log('Inside `bar`:', this.foo);
},
};
}

createObject.call({foo: 21}).bar(); // override `this` inside createObject








// Example using a arrow function
function createObject() {
console.log('Inside `createObject`:', this.foo);
return {
foo: 42,
bar: () => console.log('Inside `bar`:', this.foo),
};
}

createObject.call({foo: 21}).bar(); // override `this` inside createObject





In the function expression case, this refers to the object that was created inside the createObject. In the arrow function case, this refers to this of createObject itself.



This makes arrow functions useful if you need to access the this of the current environment:



// currently common pattern
var that = this;
getData(function(data) {
that.data = data;
});

// better alternative with arrow functions
getData(data => {
this.data = data;
});


Note that this also means that is not possible to set an arrow function's this with .bind or .call.



If you are not very familiar with this, consider reading




  • MDN - this

  • YDKJS - this & Object prototypes


2. Arrow functions cannot be called with new



ES2015 distinguishes between functions that are callable and functions that are constructable. If a function is constructable, it can be called with new, i.e. new User(). If a function is callable, it can be called without new (i.e. normal function call).



Functions created through function declarations / expressions are both constructable and callable.

Arrow functions (and methods) are only callable.
class constructors are only constructable.



If you are trying to call a non-callable function or to construct a non-constructable function, you will get a runtime error.





Knowing this, we can state the following.



Replaceable:




  • Functions that don't use this or arguments.

  • Functions that are used with .bind(this)


Not replaceable:




  • Constructor functions

  • Function / methods added to a prototype (because they usually use this)

  • Variadic functions (if they use arguments (see below))




Lets have a closer look at this using your examples:



Constructor function



This won't work because arrow functions cannot be called with new. Keep using a function declaration / expression or use class.



Prototype methods



Most likely not, because prototype methods usually use this to access the instance. If they don't use this, then you can replace it. However, if you primarily care for concise syntax, use class with its concise method syntax:



class User {
constructor(name) {
this.name = name;
}

getName() {
return this.name;
}
}


Object methods



Similarly for methods in an object literal. If the method wants to reference the object itself via this, keep using function expressions, or use the new method syntax:



const obj = {
getName() {
// ...
},
};


Callbacks



It depends. You should definitely replace it if you you are aliasing the outer this or are using .bind(this):



// old
setTimeout(function() {
// ...
}.bind(this), 500);

// new
setTimeout(() => {
// ...
}, 500);


But: If the code which calls the callback explicitly sets this to a specific value, as is often the case with event handlers, especially with jQuery, and the callback uses this (or arguments), you cannot use an arrow function!



Variadic functions



Since arrow functions don't have their own arguments, you cannot simply replace them with an arrow function. However, ES2015 introduces an alternative to using arguments: the rest parameter.



// old
function sum() {
let args = .slice.call(arguments);
// ...
}

// new
const sum = (...args) => {
// ...
};




Related question:




  • When should I use Arrow functions in ECMAScript 6?

  • Do ES6 arrow functions have their own arguments or not?

  • What are the differences (if any) between ES6 arrow functions and functions bound with Function.prototype.bind?

  • How to use ES6 arrow in class methods?


Further resources:




  • MDN - Arrow functions

  • YDKJS - Arrow functions






share|improve this answer



















  • 3




    Possibly worth mentioning that the lexical this also affects super and that they have no .prototype.
    – loganfsmyth
    Dec 18 '15 at 22:13






  • 1




    It would also be good to mention that they aren't syntactically interchangeable -- an arrow function (AssignmentExpression) can't just be dropped in everywhere a function expression (PrimaryExpression) can and it trips people up fairly frequently (especially since there've been parsing errors in major JS implementations).
    – JMM
    Apr 1 '16 at 22:49










  • @JMM: "it trips people up fairly frequently" can you provide a concrete example? Skimming over the spec, it seems that the places where you can put a FE but not an AF would result in runtime errors anyway...
    – Felix Kling
    Apr 1 '16 at 22:54










  • Sure, I mean stuff like trying to immediately invoke an arrow function like a function expression (() => {}()) or do something like x || () => {}. That's what I mean: runtime (parse) errors. (And even though that's the case, fairly frequently people think the error is in error.) Are you just trying to cover logic errors that would go unnoticed because they don't necessarily error when parsed or executed? new'ing one is a runtime error right?
    – JMM
    Apr 1 '16 at 23:27










  • Here are some links of it coming up in the wild: substack/node-browserify#1499, babel/babel-eslint#245 (this is an async arrow, but I think it's the same basic issue), and a bunch of issues on Babel that are hard to find now, but here's one T2847.
    – JMM
    Apr 1 '16 at 23:27



















2














Look at this Plnkr example



The variable this is very different timesCalled increments only by 1 each time the button is called. Which answers my personal question:



.click( () => { } )



and



.click(function() { })



both create the same number of functions when used in a loop as you can see from the Guid count in the Plnkr.






share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f34361379%2farrow-function-vs-function-declaration-expressions-are-they-equivalent-exch%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    471














    tl;dr: No! Arrow functions and function declarations / expressions are not equivalent and cannot be replaced blindly.

    If the function you want to replace does not use this, arguments and is not called with new, then yes.





    As so often: it depends. Arrow functions have different behavior than function declarations / expressions, so lets have a look at the differences first:



    1. Lexical this and arguments



    Arrow functions don't have their own this or arguments binding. Instead, those identifiers are resolved in the lexical scope like any other variable. That means that inside an arrow function, this and arguments refer to the values of this and arguments in the environment the arrow function is defined in (i.e. "outside" the arrow function):






    // Example using a function expression
    function createObject() {
    console.log('Inside `createObject`:', this.foo);
    return {
    foo: 42,
    bar: function() {
    console.log('Inside `bar`:', this.foo);
    },
    };
    }

    createObject.call({foo: 21}).bar(); // override `this` inside createObject








    // Example using a arrow function
    function createObject() {
    console.log('Inside `createObject`:', this.foo);
    return {
    foo: 42,
    bar: () => console.log('Inside `bar`:', this.foo),
    };
    }

    createObject.call({foo: 21}).bar(); // override `this` inside createObject





    In the function expression case, this refers to the object that was created inside the createObject. In the arrow function case, this refers to this of createObject itself.



    This makes arrow functions useful if you need to access the this of the current environment:



    // currently common pattern
    var that = this;
    getData(function(data) {
    that.data = data;
    });

    // better alternative with arrow functions
    getData(data => {
    this.data = data;
    });


    Note that this also means that is not possible to set an arrow function's this with .bind or .call.



    If you are not very familiar with this, consider reading




    • MDN - this

    • YDKJS - this & Object prototypes


    2. Arrow functions cannot be called with new



    ES2015 distinguishes between functions that are callable and functions that are constructable. If a function is constructable, it can be called with new, i.e. new User(). If a function is callable, it can be called without new (i.e. normal function call).



    Functions created through function declarations / expressions are both constructable and callable.

    Arrow functions (and methods) are only callable.
    class constructors are only constructable.



    If you are trying to call a non-callable function or to construct a non-constructable function, you will get a runtime error.





    Knowing this, we can state the following.



    Replaceable:




    • Functions that don't use this or arguments.

    • Functions that are used with .bind(this)


    Not replaceable:




    • Constructor functions

    • Function / methods added to a prototype (because they usually use this)

    • Variadic functions (if they use arguments (see below))




    Lets have a closer look at this using your examples:



    Constructor function



    This won't work because arrow functions cannot be called with new. Keep using a function declaration / expression or use class.



    Prototype methods



    Most likely not, because prototype methods usually use this to access the instance. If they don't use this, then you can replace it. However, if you primarily care for concise syntax, use class with its concise method syntax:



    class User {
    constructor(name) {
    this.name = name;
    }

    getName() {
    return this.name;
    }
    }


    Object methods



    Similarly for methods in an object literal. If the method wants to reference the object itself via this, keep using function expressions, or use the new method syntax:



    const obj = {
    getName() {
    // ...
    },
    };


    Callbacks



    It depends. You should definitely replace it if you you are aliasing the outer this or are using .bind(this):



    // old
    setTimeout(function() {
    // ...
    }.bind(this), 500);

    // new
    setTimeout(() => {
    // ...
    }, 500);


    But: If the code which calls the callback explicitly sets this to a specific value, as is often the case with event handlers, especially with jQuery, and the callback uses this (or arguments), you cannot use an arrow function!



    Variadic functions



    Since arrow functions don't have their own arguments, you cannot simply replace them with an arrow function. However, ES2015 introduces an alternative to using arguments: the rest parameter.



    // old
    function sum() {
    let args = .slice.call(arguments);
    // ...
    }

    // new
    const sum = (...args) => {
    // ...
    };




    Related question:




    • When should I use Arrow functions in ECMAScript 6?

    • Do ES6 arrow functions have their own arguments or not?

    • What are the differences (if any) between ES6 arrow functions and functions bound with Function.prototype.bind?

    • How to use ES6 arrow in class methods?


    Further resources:




    • MDN - Arrow functions

    • YDKJS - Arrow functions






    share|improve this answer



















    • 3




      Possibly worth mentioning that the lexical this also affects super and that they have no .prototype.
      – loganfsmyth
      Dec 18 '15 at 22:13






    • 1




      It would also be good to mention that they aren't syntactically interchangeable -- an arrow function (AssignmentExpression) can't just be dropped in everywhere a function expression (PrimaryExpression) can and it trips people up fairly frequently (especially since there've been parsing errors in major JS implementations).
      – JMM
      Apr 1 '16 at 22:49










    • @JMM: "it trips people up fairly frequently" can you provide a concrete example? Skimming over the spec, it seems that the places where you can put a FE but not an AF would result in runtime errors anyway...
      – Felix Kling
      Apr 1 '16 at 22:54










    • Sure, I mean stuff like trying to immediately invoke an arrow function like a function expression (() => {}()) or do something like x || () => {}. That's what I mean: runtime (parse) errors. (And even though that's the case, fairly frequently people think the error is in error.) Are you just trying to cover logic errors that would go unnoticed because they don't necessarily error when parsed or executed? new'ing one is a runtime error right?
      – JMM
      Apr 1 '16 at 23:27










    • Here are some links of it coming up in the wild: substack/node-browserify#1499, babel/babel-eslint#245 (this is an async arrow, but I think it's the same basic issue), and a bunch of issues on Babel that are hard to find now, but here's one T2847.
      – JMM
      Apr 1 '16 at 23:27
















    471














    tl;dr: No! Arrow functions and function declarations / expressions are not equivalent and cannot be replaced blindly.

    If the function you want to replace does not use this, arguments and is not called with new, then yes.





    As so often: it depends. Arrow functions have different behavior than function declarations / expressions, so lets have a look at the differences first:



    1. Lexical this and arguments



    Arrow functions don't have their own this or arguments binding. Instead, those identifiers are resolved in the lexical scope like any other variable. That means that inside an arrow function, this and arguments refer to the values of this and arguments in the environment the arrow function is defined in (i.e. "outside" the arrow function):






    // Example using a function expression
    function createObject() {
    console.log('Inside `createObject`:', this.foo);
    return {
    foo: 42,
    bar: function() {
    console.log('Inside `bar`:', this.foo);
    },
    };
    }

    createObject.call({foo: 21}).bar(); // override `this` inside createObject








    // Example using a arrow function
    function createObject() {
    console.log('Inside `createObject`:', this.foo);
    return {
    foo: 42,
    bar: () => console.log('Inside `bar`:', this.foo),
    };
    }

    createObject.call({foo: 21}).bar(); // override `this` inside createObject





    In the function expression case, this refers to the object that was created inside the createObject. In the arrow function case, this refers to this of createObject itself.



    This makes arrow functions useful if you need to access the this of the current environment:



    // currently common pattern
    var that = this;
    getData(function(data) {
    that.data = data;
    });

    // better alternative with arrow functions
    getData(data => {
    this.data = data;
    });


    Note that this also means that is not possible to set an arrow function's this with .bind or .call.



    If you are not very familiar with this, consider reading




    • MDN - this

    • YDKJS - this & Object prototypes


    2. Arrow functions cannot be called with new



    ES2015 distinguishes between functions that are callable and functions that are constructable. If a function is constructable, it can be called with new, i.e. new User(). If a function is callable, it can be called without new (i.e. normal function call).



    Functions created through function declarations / expressions are both constructable and callable.

    Arrow functions (and methods) are only callable.
    class constructors are only constructable.



    If you are trying to call a non-callable function or to construct a non-constructable function, you will get a runtime error.





    Knowing this, we can state the following.



    Replaceable:




    • Functions that don't use this or arguments.

    • Functions that are used with .bind(this)


    Not replaceable:




    • Constructor functions

    • Function / methods added to a prototype (because they usually use this)

    • Variadic functions (if they use arguments (see below))




    Lets have a closer look at this using your examples:



    Constructor function



    This won't work because arrow functions cannot be called with new. Keep using a function declaration / expression or use class.



    Prototype methods



    Most likely not, because prototype methods usually use this to access the instance. If they don't use this, then you can replace it. However, if you primarily care for concise syntax, use class with its concise method syntax:



    class User {
    constructor(name) {
    this.name = name;
    }

    getName() {
    return this.name;
    }
    }


    Object methods



    Similarly for methods in an object literal. If the method wants to reference the object itself via this, keep using function expressions, or use the new method syntax:



    const obj = {
    getName() {
    // ...
    },
    };


    Callbacks



    It depends. You should definitely replace it if you you are aliasing the outer this or are using .bind(this):



    // old
    setTimeout(function() {
    // ...
    }.bind(this), 500);

    // new
    setTimeout(() => {
    // ...
    }, 500);


    But: If the code which calls the callback explicitly sets this to a specific value, as is often the case with event handlers, especially with jQuery, and the callback uses this (or arguments), you cannot use an arrow function!



    Variadic functions



    Since arrow functions don't have their own arguments, you cannot simply replace them with an arrow function. However, ES2015 introduces an alternative to using arguments: the rest parameter.



    // old
    function sum() {
    let args = .slice.call(arguments);
    // ...
    }

    // new
    const sum = (...args) => {
    // ...
    };




    Related question:




    • When should I use Arrow functions in ECMAScript 6?

    • Do ES6 arrow functions have their own arguments or not?

    • What are the differences (if any) between ES6 arrow functions and functions bound with Function.prototype.bind?

    • How to use ES6 arrow in class methods?


    Further resources:




    • MDN - Arrow functions

    • YDKJS - Arrow functions






    share|improve this answer



















    • 3




      Possibly worth mentioning that the lexical this also affects super and that they have no .prototype.
      – loganfsmyth
      Dec 18 '15 at 22:13






    • 1




      It would also be good to mention that they aren't syntactically interchangeable -- an arrow function (AssignmentExpression) can't just be dropped in everywhere a function expression (PrimaryExpression) can and it trips people up fairly frequently (especially since there've been parsing errors in major JS implementations).
      – JMM
      Apr 1 '16 at 22:49










    • @JMM: "it trips people up fairly frequently" can you provide a concrete example? Skimming over the spec, it seems that the places where you can put a FE but not an AF would result in runtime errors anyway...
      – Felix Kling
      Apr 1 '16 at 22:54










    • Sure, I mean stuff like trying to immediately invoke an arrow function like a function expression (() => {}()) or do something like x || () => {}. That's what I mean: runtime (parse) errors. (And even though that's the case, fairly frequently people think the error is in error.) Are you just trying to cover logic errors that would go unnoticed because they don't necessarily error when parsed or executed? new'ing one is a runtime error right?
      – JMM
      Apr 1 '16 at 23:27










    • Here are some links of it coming up in the wild: substack/node-browserify#1499, babel/babel-eslint#245 (this is an async arrow, but I think it's the same basic issue), and a bunch of issues on Babel that are hard to find now, but here's one T2847.
      – JMM
      Apr 1 '16 at 23:27














    471












    471








    471






    tl;dr: No! Arrow functions and function declarations / expressions are not equivalent and cannot be replaced blindly.

    If the function you want to replace does not use this, arguments and is not called with new, then yes.





    As so often: it depends. Arrow functions have different behavior than function declarations / expressions, so lets have a look at the differences first:



    1. Lexical this and arguments



    Arrow functions don't have their own this or arguments binding. Instead, those identifiers are resolved in the lexical scope like any other variable. That means that inside an arrow function, this and arguments refer to the values of this and arguments in the environment the arrow function is defined in (i.e. "outside" the arrow function):






    // Example using a function expression
    function createObject() {
    console.log('Inside `createObject`:', this.foo);
    return {
    foo: 42,
    bar: function() {
    console.log('Inside `bar`:', this.foo);
    },
    };
    }

    createObject.call({foo: 21}).bar(); // override `this` inside createObject








    // Example using a arrow function
    function createObject() {
    console.log('Inside `createObject`:', this.foo);
    return {
    foo: 42,
    bar: () => console.log('Inside `bar`:', this.foo),
    };
    }

    createObject.call({foo: 21}).bar(); // override `this` inside createObject





    In the function expression case, this refers to the object that was created inside the createObject. In the arrow function case, this refers to this of createObject itself.



    This makes arrow functions useful if you need to access the this of the current environment:



    // currently common pattern
    var that = this;
    getData(function(data) {
    that.data = data;
    });

    // better alternative with arrow functions
    getData(data => {
    this.data = data;
    });


    Note that this also means that is not possible to set an arrow function's this with .bind or .call.



    If you are not very familiar with this, consider reading




    • MDN - this

    • YDKJS - this & Object prototypes


    2. Arrow functions cannot be called with new



    ES2015 distinguishes between functions that are callable and functions that are constructable. If a function is constructable, it can be called with new, i.e. new User(). If a function is callable, it can be called without new (i.e. normal function call).



    Functions created through function declarations / expressions are both constructable and callable.

    Arrow functions (and methods) are only callable.
    class constructors are only constructable.



    If you are trying to call a non-callable function or to construct a non-constructable function, you will get a runtime error.





    Knowing this, we can state the following.



    Replaceable:




    • Functions that don't use this or arguments.

    • Functions that are used with .bind(this)


    Not replaceable:




    • Constructor functions

    • Function / methods added to a prototype (because they usually use this)

    • Variadic functions (if they use arguments (see below))




    Lets have a closer look at this using your examples:



    Constructor function



    This won't work because arrow functions cannot be called with new. Keep using a function declaration / expression or use class.



    Prototype methods



    Most likely not, because prototype methods usually use this to access the instance. If they don't use this, then you can replace it. However, if you primarily care for concise syntax, use class with its concise method syntax:



    class User {
    constructor(name) {
    this.name = name;
    }

    getName() {
    return this.name;
    }
    }


    Object methods



    Similarly for methods in an object literal. If the method wants to reference the object itself via this, keep using function expressions, or use the new method syntax:



    const obj = {
    getName() {
    // ...
    },
    };


    Callbacks



    It depends. You should definitely replace it if you you are aliasing the outer this or are using .bind(this):



    // old
    setTimeout(function() {
    // ...
    }.bind(this), 500);

    // new
    setTimeout(() => {
    // ...
    }, 500);


    But: If the code which calls the callback explicitly sets this to a specific value, as is often the case with event handlers, especially with jQuery, and the callback uses this (or arguments), you cannot use an arrow function!



    Variadic functions



    Since arrow functions don't have their own arguments, you cannot simply replace them with an arrow function. However, ES2015 introduces an alternative to using arguments: the rest parameter.



    // old
    function sum() {
    let args = .slice.call(arguments);
    // ...
    }

    // new
    const sum = (...args) => {
    // ...
    };




    Related question:




    • When should I use Arrow functions in ECMAScript 6?

    • Do ES6 arrow functions have their own arguments or not?

    • What are the differences (if any) between ES6 arrow functions and functions bound with Function.prototype.bind?

    • How to use ES6 arrow in class methods?


    Further resources:




    • MDN - Arrow functions

    • YDKJS - Arrow functions






    share|improve this answer














    tl;dr: No! Arrow functions and function declarations / expressions are not equivalent and cannot be replaced blindly.

    If the function you want to replace does not use this, arguments and is not called with new, then yes.





    As so often: it depends. Arrow functions have different behavior than function declarations / expressions, so lets have a look at the differences first:



    1. Lexical this and arguments



    Arrow functions don't have their own this or arguments binding. Instead, those identifiers are resolved in the lexical scope like any other variable. That means that inside an arrow function, this and arguments refer to the values of this and arguments in the environment the arrow function is defined in (i.e. "outside" the arrow function):






    // Example using a function expression
    function createObject() {
    console.log('Inside `createObject`:', this.foo);
    return {
    foo: 42,
    bar: function() {
    console.log('Inside `bar`:', this.foo);
    },
    };
    }

    createObject.call({foo: 21}).bar(); // override `this` inside createObject








    // Example using a arrow function
    function createObject() {
    console.log('Inside `createObject`:', this.foo);
    return {
    foo: 42,
    bar: () => console.log('Inside `bar`:', this.foo),
    };
    }

    createObject.call({foo: 21}).bar(); // override `this` inside createObject





    In the function expression case, this refers to the object that was created inside the createObject. In the arrow function case, this refers to this of createObject itself.



    This makes arrow functions useful if you need to access the this of the current environment:



    // currently common pattern
    var that = this;
    getData(function(data) {
    that.data = data;
    });

    // better alternative with arrow functions
    getData(data => {
    this.data = data;
    });


    Note that this also means that is not possible to set an arrow function's this with .bind or .call.



    If you are not very familiar with this, consider reading




    • MDN - this

    • YDKJS - this & Object prototypes


    2. Arrow functions cannot be called with new



    ES2015 distinguishes between functions that are callable and functions that are constructable. If a function is constructable, it can be called with new, i.e. new User(). If a function is callable, it can be called without new (i.e. normal function call).



    Functions created through function declarations / expressions are both constructable and callable.

    Arrow functions (and methods) are only callable.
    class constructors are only constructable.



    If you are trying to call a non-callable function or to construct a non-constructable function, you will get a runtime error.





    Knowing this, we can state the following.



    Replaceable:




    • Functions that don't use this or arguments.

    • Functions that are used with .bind(this)


    Not replaceable:




    • Constructor functions

    • Function / methods added to a prototype (because they usually use this)

    • Variadic functions (if they use arguments (see below))




    Lets have a closer look at this using your examples:



    Constructor function



    This won't work because arrow functions cannot be called with new. Keep using a function declaration / expression or use class.



    Prototype methods



    Most likely not, because prototype methods usually use this to access the instance. If they don't use this, then you can replace it. However, if you primarily care for concise syntax, use class with its concise method syntax:



    class User {
    constructor(name) {
    this.name = name;
    }

    getName() {
    return this.name;
    }
    }


    Object methods



    Similarly for methods in an object literal. If the method wants to reference the object itself via this, keep using function expressions, or use the new method syntax:



    const obj = {
    getName() {
    // ...
    },
    };


    Callbacks



    It depends. You should definitely replace it if you you are aliasing the outer this or are using .bind(this):



    // old
    setTimeout(function() {
    // ...
    }.bind(this), 500);

    // new
    setTimeout(() => {
    // ...
    }, 500);


    But: If the code which calls the callback explicitly sets this to a specific value, as is often the case with event handlers, especially with jQuery, and the callback uses this (or arguments), you cannot use an arrow function!



    Variadic functions



    Since arrow functions don't have their own arguments, you cannot simply replace them with an arrow function. However, ES2015 introduces an alternative to using arguments: the rest parameter.



    // old
    function sum() {
    let args = .slice.call(arguments);
    // ...
    }

    // new
    const sum = (...args) => {
    // ...
    };




    Related question:




    • When should I use Arrow functions in ECMAScript 6?

    • Do ES6 arrow functions have their own arguments or not?

    • What are the differences (if any) between ES6 arrow functions and functions bound with Function.prototype.bind?

    • How to use ES6 arrow in class methods?


    Further resources:




    • MDN - Arrow functions

    • YDKJS - Arrow functions






    // Example using a function expression
    function createObject() {
    console.log('Inside `createObject`:', this.foo);
    return {
    foo: 42,
    bar: function() {
    console.log('Inside `bar`:', this.foo);
    },
    };
    }

    createObject.call({foo: 21}).bar(); // override `this` inside createObject





    // Example using a function expression
    function createObject() {
    console.log('Inside `createObject`:', this.foo);
    return {
    foo: 42,
    bar: function() {
    console.log('Inside `bar`:', this.foo);
    },
    };
    }

    createObject.call({foo: 21}).bar(); // override `this` inside createObject





    // Example using a arrow function
    function createObject() {
    console.log('Inside `createObject`:', this.foo);
    return {
    foo: 42,
    bar: () => console.log('Inside `bar`:', this.foo),
    };
    }

    createObject.call({foo: 21}).bar(); // override `this` inside createObject





    // Example using a arrow function
    function createObject() {
    console.log('Inside `createObject`:', this.foo);
    return {
    foo: 42,
    bar: () => console.log('Inside `bar`:', this.foo),
    };
    }

    createObject.call({foo: 21}).bar(); // override `this` inside createObject






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited May 23 '17 at 12:34









    Community

    11




    11










    answered Dec 18 '15 at 17:58









    Felix Kling

    545k126847906




    545k126847906








    • 3




      Possibly worth mentioning that the lexical this also affects super and that they have no .prototype.
      – loganfsmyth
      Dec 18 '15 at 22:13






    • 1




      It would also be good to mention that they aren't syntactically interchangeable -- an arrow function (AssignmentExpression) can't just be dropped in everywhere a function expression (PrimaryExpression) can and it trips people up fairly frequently (especially since there've been parsing errors in major JS implementations).
      – JMM
      Apr 1 '16 at 22:49










    • @JMM: "it trips people up fairly frequently" can you provide a concrete example? Skimming over the spec, it seems that the places where you can put a FE but not an AF would result in runtime errors anyway...
      – Felix Kling
      Apr 1 '16 at 22:54










    • Sure, I mean stuff like trying to immediately invoke an arrow function like a function expression (() => {}()) or do something like x || () => {}. That's what I mean: runtime (parse) errors. (And even though that's the case, fairly frequently people think the error is in error.) Are you just trying to cover logic errors that would go unnoticed because they don't necessarily error when parsed or executed? new'ing one is a runtime error right?
      – JMM
      Apr 1 '16 at 23:27










    • Here are some links of it coming up in the wild: substack/node-browserify#1499, babel/babel-eslint#245 (this is an async arrow, but I think it's the same basic issue), and a bunch of issues on Babel that are hard to find now, but here's one T2847.
      – JMM
      Apr 1 '16 at 23:27














    • 3




      Possibly worth mentioning that the lexical this also affects super and that they have no .prototype.
      – loganfsmyth
      Dec 18 '15 at 22:13






    • 1




      It would also be good to mention that they aren't syntactically interchangeable -- an arrow function (AssignmentExpression) can't just be dropped in everywhere a function expression (PrimaryExpression) can and it trips people up fairly frequently (especially since there've been parsing errors in major JS implementations).
      – JMM
      Apr 1 '16 at 22:49










    • @JMM: "it trips people up fairly frequently" can you provide a concrete example? Skimming over the spec, it seems that the places where you can put a FE but not an AF would result in runtime errors anyway...
      – Felix Kling
      Apr 1 '16 at 22:54










    • Sure, I mean stuff like trying to immediately invoke an arrow function like a function expression (() => {}()) or do something like x || () => {}. That's what I mean: runtime (parse) errors. (And even though that's the case, fairly frequently people think the error is in error.) Are you just trying to cover logic errors that would go unnoticed because they don't necessarily error when parsed or executed? new'ing one is a runtime error right?
      – JMM
      Apr 1 '16 at 23:27










    • Here are some links of it coming up in the wild: substack/node-browserify#1499, babel/babel-eslint#245 (this is an async arrow, but I think it's the same basic issue), and a bunch of issues on Babel that are hard to find now, but here's one T2847.
      – JMM
      Apr 1 '16 at 23:27








    3




    3




    Possibly worth mentioning that the lexical this also affects super and that they have no .prototype.
    – loganfsmyth
    Dec 18 '15 at 22:13




    Possibly worth mentioning that the lexical this also affects super and that they have no .prototype.
    – loganfsmyth
    Dec 18 '15 at 22:13




    1




    1




    It would also be good to mention that they aren't syntactically interchangeable -- an arrow function (AssignmentExpression) can't just be dropped in everywhere a function expression (PrimaryExpression) can and it trips people up fairly frequently (especially since there've been parsing errors in major JS implementations).
    – JMM
    Apr 1 '16 at 22:49




    It would also be good to mention that they aren't syntactically interchangeable -- an arrow function (AssignmentExpression) can't just be dropped in everywhere a function expression (PrimaryExpression) can and it trips people up fairly frequently (especially since there've been parsing errors in major JS implementations).
    – JMM
    Apr 1 '16 at 22:49












    @JMM: "it trips people up fairly frequently" can you provide a concrete example? Skimming over the spec, it seems that the places where you can put a FE but not an AF would result in runtime errors anyway...
    – Felix Kling
    Apr 1 '16 at 22:54




    @JMM: "it trips people up fairly frequently" can you provide a concrete example? Skimming over the spec, it seems that the places where you can put a FE but not an AF would result in runtime errors anyway...
    – Felix Kling
    Apr 1 '16 at 22:54












    Sure, I mean stuff like trying to immediately invoke an arrow function like a function expression (() => {}()) or do something like x || () => {}. That's what I mean: runtime (parse) errors. (And even though that's the case, fairly frequently people think the error is in error.) Are you just trying to cover logic errors that would go unnoticed because they don't necessarily error when parsed or executed? new'ing one is a runtime error right?
    – JMM
    Apr 1 '16 at 23:27




    Sure, I mean stuff like trying to immediately invoke an arrow function like a function expression (() => {}()) or do something like x || () => {}. That's what I mean: runtime (parse) errors. (And even though that's the case, fairly frequently people think the error is in error.) Are you just trying to cover logic errors that would go unnoticed because they don't necessarily error when parsed or executed? new'ing one is a runtime error right?
    – JMM
    Apr 1 '16 at 23:27












    Here are some links of it coming up in the wild: substack/node-browserify#1499, babel/babel-eslint#245 (this is an async arrow, but I think it's the same basic issue), and a bunch of issues on Babel that are hard to find now, but here's one T2847.
    – JMM
    Apr 1 '16 at 23:27




    Here are some links of it coming up in the wild: substack/node-browserify#1499, babel/babel-eslint#245 (this is an async arrow, but I think it's the same basic issue), and a bunch of issues on Babel that are hard to find now, but here's one T2847.
    – JMM
    Apr 1 '16 at 23:27













    2














    Look at this Plnkr example



    The variable this is very different timesCalled increments only by 1 each time the button is called. Which answers my personal question:



    .click( () => { } )



    and



    .click(function() { })



    both create the same number of functions when used in a loop as you can see from the Guid count in the Plnkr.






    share|improve this answer


























      2














      Look at this Plnkr example



      The variable this is very different timesCalled increments only by 1 each time the button is called. Which answers my personal question:



      .click( () => { } )



      and



      .click(function() { })



      both create the same number of functions when used in a loop as you can see from the Guid count in the Plnkr.






      share|improve this answer
























        2












        2








        2






        Look at this Plnkr example



        The variable this is very different timesCalled increments only by 1 each time the button is called. Which answers my personal question:



        .click( () => { } )



        and



        .click(function() { })



        both create the same number of functions when used in a loop as you can see from the Guid count in the Plnkr.






        share|improve this answer












        Look at this Plnkr example



        The variable this is very different timesCalled increments only by 1 each time the button is called. Which answers my personal question:



        .click( () => { } )



        and



        .click(function() { })



        both create the same number of functions when used in a loop as you can see from the Guid count in the Plnkr.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Sep 12 '16 at 14:01









        ansielf

        1,04411132




        1,04411132






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f34361379%2farrow-function-vs-function-declaration-expressions-are-they-equivalent-exch%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            這個網誌中的熱門文章

            Hercules Kyvelos

            Tangent Lines Diagram Along Smooth Curve

            Yusuf al-Mu'taman ibn Hud