Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are Arrow Functions Untraceable?

I just learned that, writing this:

const setName = name => {
  // set name here
}

is bad as opposed to this

function setName(name) {
  //set name here
}

The reason was that the first approach makes it difficult to debug issues related to that function since it will not appear in the stack trace.

Question: Why would this not appear in the stack trace?

like image 350
Siya Mzam Avatar asked Feb 13 '18 10:02

Siya Mzam


People also ask

What are the disadvantages of arrow function?

Arrow functions aren't suitable for call , apply and bind methods, which generally rely on establishing a scope. Arrow functions cannot be used as constructors. Arrow functions cannot use yield , within its body.

Is arrow function anonymous in JavaScript?

ES6 introduced a new and shorter way of declaring an anonymous function, which is known as Arrow Functions.

Are anonymous functions and arrow functions the same?

The main difference between anonymous functions and arrow functions in PHP is the use of the use keyword. In order to have access to the scope outside of the anonymous function, you must use the use keyword. Arrow functions automatically have access to scope outside of the function.

What makes arrow functions different from other anonymous functions?

Unlike regular functions, arrow functions do not have their own this . The value of this inside an arrow function remains the same throughout the lifecycle of the function and is always bound to the value of this in the closest non-arrow parent function.


1 Answers

Are Arrow Functions Untraceable?

No, they're just as traceable as any other function, if you're referring to being able to debug them, stack traces, etc.

I just learned that, writing this...is bad as opposed to this...

No, it isn't. It's different. It's not objectively bad.ΒΉ

The reason was that the first approach makes it difficult to debug issues related to that function since it will not appear in the stack trace.

Yes it will. If someone told you it won't, they're mistaken πŸ™‚ β€” which is understandable, because arrow functions don't have a declaration syntax, and their expression syntax doesn't have anywhere to put a name; so it seems reasonable to assume they don't get names. While some don't, many, many do (see my answer here for details on how and when), including yours. Let's see the name in a stack trace:

const setName = name => {
    throw new Error("Ack!");
};

const wrapper = name => setName(name);

wrapper("foo");
Look in the real console.

If you run that, you'll see this in the console:

Uncaught Error: Ack! at setName (js:14) at wrapper (js:17) at js:19

Notice how both setName and wrapper are listed.

So even functions created with anonymous syntax can (somewhat paradoxically) get names, and often do. This isn't just something that a specific JavaScript engine does to be helpful (though it used to be), it's dictated by the JavaScript specification.

So what is anonymous function syntax vs. named function syntax? Let's quickly review five common ways to create functions (this isn't a full listΒ β€” I provide one hereΒ β€” just five common ones):

  • A function declaration (the ^ markers indicate the declaration itself, the βˆ’ markers indicate the contents of the function):

        function example1() { return 42; }
    // ^^^^^^^^^^^^^^^^^^^^^βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’^
    
  • A named function expression (relatively rare):

    const example = function example2() { return 42; };
    //              ^^^^^^^^^^^^^^^^^^^^^βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’^
    
  • An anonymous function expression:

    const example3 = function() { return 42; };
    //               ^^^^^^^^^^^^βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’^
    
    
  • A "verbose" arrow function expression (has a function body block, no implied return):

    const example4 = () => { return 42; };
    //               ^^^^^^^βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’βˆ’^
    
  • A "concise" arrow function expression (no function body block, implied return):

    const example5 = () => 42;
    //               ^^^^^βˆ’βˆ’βˆ’
    

function declarations always include a name (with one obscure exceptionΒ²). function expressions can be named or anonymous. All arrow function expressions are anonymous. But all of the functions in those examples have names (example1, example2, example3, example4, and example5). Their names are assigned based on the expression they're a part of. (See the answer linked earlier for details.)

To be clear: Some arrow functions don't have names, just like some traditional functions don't have names. For instance, neither of these functions has a name:

result = theArray.map(s => s.toUpperCase());
result = theArray.map(function(s) { return s.toUpperCase(); });

The only advantage with regard to names that traditional functions have over arrow functions that their expression syntax lets you specify a name explicitly rather than relying on context, like this:

result = theArray.map(function upperCaseCallback(s) { return s.toUpperCase(); });

There's no way to do that in a single expression with an arrow function, you'd need something like this instead:

const upperCaseCallback = s => s.toUpperCase();
result = theArray.map(upperCaseCallback);

But even though some arrow functions are anonymous, your example isn't.


ΒΉ In fact, there are some arguments the other way: The arrow function doesn't have a prototype property and an object associated with it, and calling it doesn't require setting up a new this binding or arguments pseudo-object and binding (since arrows don't have their own this, arguments, or [where relevant] super). So in theory, it's lighter-weight. Countering that is some question of readabilityΒ β€” "I didn't realize that was a function" (though I suspect people will get used to arrow functions)Β β€” and the hoisting behavior of function declarations is sometimes useful and has no arrow analogue.

Β² "function declarations always include a name (with one obscure exceptionΒ²)." The obscure exception is this:

export default function() { }

That's an exported function declaration, not a function expression, with hoisting and such. It's the only place a function declaration can have no name specified. (The function does get a name, though: default.)

like image 173
T.J. Crowder Avatar answered Sep 17 '22 04:09

T.J. Crowder