Monday, May 20, 2024
13
rated 0 times [  19] [ 6]  / answers: 1 / hits: 120597  / 10 Years ago, fri, january 16, 2015, 12:00:00

I have a function that I am trying to convert to the new arrow syntax in ES6. It is a named function:


function sayHello(name) {
console.log(name + ' says hello');
}

Is there a way to give it a name without a var statement:


var sayHello = (name) => {
console.log(name + ' says hello');
}

Obviously, I can only use this function after I have defined it. Something like following:


sayHello = (name) => {
console.log(name + ' says hello');
}

Is there a new way to do this in ES6?


More From » ecmascript-6

 Answers
11

How do I write a named arrow function in ES2015?



You do it the way you ruled out in your question: You put it on the right-hand side of an assignment or property initializer where the variable or property name can reasonably be used as a name by the JavaScript engine. There's no other way to do it, but doing that is correct and fully covered by the specification. (It also works for traditional anonymous function expressions.)


Per spec, this function has a true name, sayHello:




const sayHello = (name) => {
console.log(name + ' says hello');
};
console.log(sayHello.name); // sayHello




This is currently defined in Assignment Operators > Runtime Semantics: Evaluation where it does the abstract NamedEvalution operation (currently step 1.c.i). (You can see everywhere this applies by hovering your mouse over NamedEvalution in the header there and clicking "References".) (Previously, before ES2019, Assignment Operators > Runtime Semantics: Evaluation used the abstract SetFunctionName operation, step 1.e.iii, but in ES2019 onward this specification abstraction was replaced with NamedEvalution.)


Similiarly, PropertyDefinitionEvaluation uses NamedEvalution and thus gives this function a true name:


let o = {
sayHello: (name) => {
console.log(`${name} says hello`);
}
};

Modern engines set the internal name of the function for statements like that already.


Note: For this name inference to occur, the function expression has to be directly assigned to the target. For instance, this doesn't infer the name:




const sayHello = (void 0, (name) => {
console.log(name + ' says hello');
});
console.log(sayHello.name); //




That's because the function expression isn't being directly assigned to the const, it's an operand to a further operator (in that case, the comma operator, but it would be the same for [say] true && (name) => { }).


For example, in Chrome, Edge (Chromium-based, v79 onward), or Firefox, open the web console and then run this snippet:




use strict;
let foo = () => { throw new Error(); };
console.log(foo.name is: + foo.name);
try {
foo();
} catch (e) {
console.log(e.stack);
}




On Chrome 51 and above and Firefox 53 and above (and "Legacy" Edge 13 and above with an experimental flag, or "Chromium" Edge 79 onward), when you run that, you'll see:



foo.name is: foo
Error
at foo (http://stacksnippets.net/js:14:23)
at http://stacksnippets.net/js:17:3

Note the foo.name is: foo and Error...at foo.


On Chrome 50 and earlier, Firefox 52 and earlier, and Legacy Edge without the experimental flag, you'll see this instead because they don't have the Function#name property (yet):



foo.name is:
Error
at foo (http://stacksnippets.net/js:14:23)
at http://stacksnippets.net/js:17:3

Note that the name is missing from foo.name is:, but it is shown in the stack trace. It's just that actually implementing the name property on the function was lower priority than some other ES2015 features; Chrome and Firefox have it now; Edge has it behind a flag, presumably it won't be behind the flag a lot longer.



Obviously, I can only use this function after I have defined it



Correct. There is no function declaration syntax for arrow functions, only function expression syntax, and there's no arrow equivalent to the name in an old-style named function expression (var f = function foo() { };). So there's no equivalent to:




console.log(function fact(n) {
if (n < 0) {
throw new Error(Not defined for negative numbers);
}
return n == 0 ? 1 : n * fact(n - 1);
}(5)); // 120




You have to break it into two expressions (I'd argue you should do that anyway):




const fact = n => {
if (n < 0) {
throw new Error(Not defined for negative numbers.);
}
return n == 0 ? 1 : n * fact(n - 1);
};
console.log(fact(5));




Of course, if you have to put this where a single expression is required, you can always...use an arrow function:




console.log((() => {
const fact = n => {
if (n < 0) {
throw new Error(Not defined for negative numbers.);
}
return n == 0 ? 1 : n * fact(n - 1);
};
return fact(5);
})()); // 120




I ain't sayin' that's pretty, but it works if you absolutely, positively need a single expression wrapper.




Side note: What if you don't want a function to get its name from the identifier you're assigning to? That, suppose you don't want example.name to be "example" here?




const example = () => {};
console.log(example.name); // example




You can avoid it by using any expression that doesn't use NamedEvaluation. Probably the most popular way to do this sort of thing is the comma operator:




const example = (0, () => {});
// ^^^−−−−−−−−−^
console.log(example.name); //




The 0 there can be anything you want, it's evaluated and then thrown away so 0 is a popular choice. Passing the function through the comma operator breaks the direct link between the assignment and the function expression, preventing NamedEvaluation from providing the name example for the function. (This is similar to other famous uses of the comma operator, like (0, object.example)() which calls object.example without making object the value of this within the call, or (0, eval)("code"), which does an eval, but not in the current scope as it normally would.)


(Thank you to Sebastian Simon for raising this point in the comments.)


[#68193] Tuesday, January 13, 2015, 10 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
tonisandyp

Total Points: 694
Total Questions: 97
Total Answers: 77

Location: British Indian Ocean Territory
Member since Tue, Feb 22, 2022
2 Years ago
;