How does an anonymous function know its name? - javascript

Consider the following code.
const foo = () => {};
console.log(foo.name); // prints foo
const bar = foo;
console.log(bar.name); // prints foo again
Please point out what is wrong with my reasoning about the statement const foo = () => {};. The expression () => {} evaluates to an anonymous function object and the statement binds the name foo to that object. Surely the value of the expression () => {} does not know it has name foo, but somehow it knows after foo is bound to it. But how did that happen? I assume that = does not alter the right-hand side and lines 3 and 4 behave as I expected.

According to the specification, when a variable declaration is evaluated and the initializer is an anonymous function definition, then that definition is evaluated in a special way, passing along the name of the variable to be used as function name:
LexicalBinding : BindingIdentifier Initializer
1. Let bindingId be StringValue of BindingIdentifier.
2. Let lhs be ! ResolveBinding(bindingId).
3. If IsAnonymousFunctionDefinition(Initializer) is true, then
   a. Let value be ? NamedEvaluation of Initializer with argument bindingId.
...
Something similar happens when evaluating an assignment expression.

Line 1 of your code technically isn't an anonymous function, it's a "implicitly named" function expression (or as the mdn also calls it, an "unnamed function").
From the mdn:
The variable to which the function expression is assigned will have a name property. The name doesn't change if it's assigned to a different variable. If function name is omitted, it will be the variable name (implicit name). If function name is present, it will be the function name (explicit name). This also applies to arrow functions (arrows don't have a name so you can only give the variable an implicit name).
See also: Function.name#function_expression

Related

How JavaScript assigns `name` attribute of function?

In JavaScript, when I define function like this
function aaa(){}
I can later access the name by name attribute:
aaa.name
which will return
"aaa"
However, when I define function via var, it technically should be anonymous function without name attribute:
var aaa=function(){}
But instead it assumes that aaa is function name and assigns it to name attribute:
aaa.name
will also return
"aaa"
How JavaScript decides what should be the name, especially considering the fact that assignments could use more complicated scenarios:
var aaa=bbb=function(){}
or
var aaa=arr[0]=function(){}
?
Javascript declares the name variable of the function by taking the left-hand side argument that is equal to the function, which is 'aaa' in all basic cases. In the first complex definition, you declared state above Javascript will take the variable ab and assign it to a function making the name 'ab'. In the final example, you provided it sets the function equal to a pointer in memory, which is not a defined variable, this sets the name property to an empty string because arr[0] is not a variable name but a pointer to memory.
Here is a JSFiddle displaying this.
Something like this:
Inferred function names
Variables and methods can infer the name of an anonymous function from
its syntactic position (new in ECMAScript 2015).
var f = function() {};
var object = {
someMethod: function() {}
};
console.log(f.name); // "f"
console.log(object.someMethod.name); // "someMethod"
Read the entire blog. It will clear all your queries.

eval(fn) and eval(arrowFn) returns different value

As per the Mozilla docs in order to execute a function using eval it must be wrapped inside ( ) i.e. if you don't use them then it treated as a string.
eval as a string defining function requires "(" and ")" as prefix and suffix
when I execute normal function it returns undefined as expected but not in the case of ES6 functions. My Question is ES6 functions are treated differently by javascript engines or only within eval function.
var fn = "function a(){}";
var es6fn = "()=>{}";
console.log(eval(fn)); // undefined
console.log(eval(es6fn)); // ()=>{}
console.log(typeof eval(es6fn)); // ()=>{} i.e. a function
Lets take a step back and see what is actually going on here. I think you are misunderstanding the point MDN is trying to make. The only function that is executed in your example is eval. The (...) the documentation is mentioning are not for executing the function inside the string but for changing how the function definition is evaluated.
A function call would function a(){}() but the docs talk about putting the function definition inside parenthesis: (function(){}).
There are basically thee major ways to define functions:
Function declaration
function foo() {}
Function expression
var foo = function() {}
Arrow function
var foo = () => {}
To understand the difference between a function declaration and a function expression, we have to understand the difference between statements and expressions (a declaration is basically like a statement).
A statement is something that has side effects and does not produce a value. if, for, switch, etc are all statements.
An expression is something that produces a value. E.g. 5 is a number literal that produces the value 5. 5 + 3 is an expression that computes the sum of the two literals, i.e. evaluating it will return the value 8.
A function declaration is like a statement. It doesn't produce a value itself, but as a side effect, a variable is defined whose value is a function (you can see in the specification that nothing happens when a function declaration is evaluated (they have already been processed at that point)).
A function expression is very similar, but instead of defining a variable, evaluating it simply results in the function object.
And that is the reason why
eval('function a() {}') // undefined, but a is defined as side effect
eval('(function a() {})') // a function object
produce different results. The first is interpreted as function declaration. A variable a will be created, but no value is created that eval could return. In the second case, the grouping operator ((...)) forces the function definition to be interpreted as a function expression, which means that a value is produced and return by eval.
Now regarding arrow functions: There is no ambiguity here. Arrow function definitions are always expressions, i.e. evaluating them always produces a value.
eval(`() => {}`) // a function object
To sum up
While there is a difference between arrow functions and function declarations/expressions, this difference is not the reason for the results you are seeing with eval. The difference here is because of evaling a statement/declaration and an expression.
In your example, a is declared as it's a named function. In the second case, you just write an expression which is a lambda function. See here and here.
If you want to get the same effect for fn, do
`console.log(eval("var a = function(){}"))`; //`function(){}`.
First of all, EcmaScript is the "official" name for JavaScript. Now that ES2015 is finalised, it effectively just becomes JavaScript v6 to most people. So, this difference does not come from the different engin.
The origin of the different behavior comes from the result of the string which is written in the eval function. the result of the first eval string is a function definition and there is not anything to return. On the other side, the second eval is evaluating a lambda function, so the result of the eval is that function. To clear this concept, you can rewrite the code like the following:
var fn = "function a(){ return 1;}";
var es6fn = "()=>{}";
console.log(eval(fn)); // undefined
console.log(eval(es6fn)); // ()=>{}
console.log(typeof eval(es6fn)); // ()=>{} i.e. a function
console.log(a()); // call the a() function
As, you can see, the a() is defined as a function, and you can use the function after the first eval. So, the first eval is run and all back to the return value for eval function.
The documentation says nothing on function execution. The functions won't be executed, unless they are executed explicitly like (() => {})().
The quote
eval as a string defining function requires "(" and ")" as prefix and suffix
refers to interpreting the string as function expression rather than function declaration.
// will throw SyntaxError
// because function declaration requires a name
typeof eval('function (){}');
typeof eval('function a(){}') === 'undefined';
typeof eval('(function a(){})') === 'function';
typeof eval('null, function a(){}') === 'function';
typeof eval('()=>{}') === 'function';
Arrow function is always an expression, it doesn't need auxiliary constructions like comma or parentheses to interpret is an expression, here is the difference.

Definition of name property in assignment expression

Since ECMAScript 6, most function objects have a name property defined.
Now, if an anonymous function expression is assigned to a variable or is part of a property definition inside an object initializer, the identifier of the variable or the name of the property will be the value of the name property of the function object.
const a = function () {};
console.log(a.name); // a
const object = {
b : function () {}
};
console.log(object.b.name); // b
I don't have problems to understand the spec regarding the documented semantic of this behaviour, but I can't really see, why an assignment to a left hand side member expression as in the following example does not affect the name property of the function, which seems to be the case.
const object = {};
object.c = function () {};
console.log(object.c.name); //
As part of the member expression, there is obviously an indentifier which could (and should?) be used as the value of the name property. Even if the property name would be an expression inside brackets, this should be no problem, since using computed property names inside an object initializer does not prevent the name property of the anonymous function to be defined either.
It would be great, if someone could confirm that the observed behaviour is conforming to the spec and anyway, explain in short the specific semantics that apply to this syntax.
This first snippet is described under assignment operators:
e. If IsAnonymousFunctionDefinition(AssignmentExpression) and IsIdentifierRef of LeftHandSideExpression are both true, then
i. Let hasNameProperty be HasOwnProperty(rval, "name").
ii. ReturnIfAbrupt(hasNameProperty).
iii. If hasNameProperty is false, perform SetFunctionName(rval, GetReferencedName(lref)).
When you assign to a MemberExpression, as in your last snippet, IsIdentifierRef(LeftHandSideExpression) is false and no conversion takes place.
If you search the standard for IsAnonymousFunctionDefinition you'll find a couple of other cases where this logic is used (object initializers, destructuring assignments).
IsIdentifierRef is defined twice (here and here), and both definitions boil down to "if an expression is IdentifierReference return true otherwise return false", where IdentifierReference is an Identifier (the yield stuff is for backward compatibility with non-strict code).

What's the proper name the foo: function() style of creating a function in Javascript?

I'm coming across these two ways of declaring functions in Javascript.
One is an assignment expression that to declares foo to be whatever the function returns, i.e.
var foo = function(){
//do something
};
And the other way of declaring a function seems to make it a property of a larger object:
foo: function() { //do something }
I'm assuming you would use the second form when you needed to access that function in an object context, i.e.:
myobject.foo();
What is the proper name for the second form?
Both are anonymous functions, the first one assigned to a variable, the second one assigned to a property in an object literal.
Note that the assignment expression is just:
foo = something
The something happens to be an anonymous function in this case, but the term assignment expression is used for all assignments, not only for functions.
The following:
var foo = function(){
//do something
};
the right hand side is a FunctionExpression, it is different to a FunctionDeclaration in that the function isn't created until the code is executed, which is after function declarations have been processed and variable instatiation has occurred.
It is not a function declaration.
> foo: function() {
> //do something
> }
that is also a function expression, to put it in the same form as the first:
var obj = {};
obj.foo = function(){...};
and it too is only created when the code is executed. There is no practical difference between the two above, use whatever seems best.
Edit
Oh, and in a function expression, the name is optional (and generally recommended against because of issues with IE and named function expressions).

Definition vs initialization

What's the difference between declaration, definition and initialization? Example:
// Is this a declaration?
var foo;
// Did I defined object in here (but it is empty)?
var foo = {};
// Now that object is initialized with some value?
var foo = {first:"number_one"};
The first example is a declaration. You have declared a variable with the identifier foo. You haven't given it a value yet, so it will be undefined:
var foo;
console.log(foo); //undefined
The second example is a declaration and an assignment. You have assigned an empty object literal to the variable with the identifier foo. As noted in the comments, this is effectively short for:
var foo;
console.log(foo); //undefined
foo = {};
console.log(foo); //Object
The third example is another declaration and another assignment. You have assigned a different object literal to foo.
Edit (see comments)
The behaviour of your code is slightly different depending on whether you intended each example to run as an independent program, or as written (one program).
If you treat is as it's written:
Because variable declarations in JavaScript are hoisted to the top of the scope in which they appear, redeclaring variables has no effect. So the first line declares a variable foo.
The second line assigns an empty object literal to foo, and the third line assigns a different object literal to foo. Both of these assignments apply to the same foo.
What effectively happens is this:
var foo;
foo = {}; //No `var` keyword
foo = {first:"number_one"}; //No `var` keyword
If you treat each line as a separate program:
The first program declares a variable named foo. It's value is undefined.
The second program declares a variable named foo, and then assigns an empty object literal to it.
The third program declares a variable named foo and then assigns an object literal with one property to it.
You got it right.
var foo; // Is this a declaration ?
Yes, you declared that there's a variable named foo, but didn't define foo (so foo is undefined).
var foo = {} // Did I defined object in here (but it is empty) ?
Yes, now you "defined" foo... it has a value, it is no longer undefined. var foo = 5 also counts as "defining" it.
var foo = {first:"number_one"} // Now that object is initialized with some value ?
You could say that it's "initialized," but that's really just semantics. "Declared" and "defined" are a bit more meaningful.
Run the code below:
var foo;
console.dir(foo);
var foo = {};
console.dir(foo);
var foo = {first:"number_one"};
console.dir(foo);
When you declare a variable with var foo; you actually ensure that it will belong to the scope where you've defined it. What you call definition and initialization is in fact a value assignment.
Consider following piece of code as an example:
(function () {
// definition
var foo;
function assignFoo(x) {
// assignment
foo = x;
}
assignFoo(5);
console.log(foo);
})();
To say, you're not always supposed to assign value within the scope of definition. But it is the most common use case which is usually accomplished with var foo = 5.
Thats it.

Categories