Deep understanding of anonymous functions in JavaScript

This article is derived from a question from Zhihu:

The same is to determine the functions at runtime, why bis anonymous function?


For this seemingly simple question, I worked in the browser for more than an hour. And it seems to have discovered 2 suspected bugs in FireFox/Chrome Devtools.

In the ES specification, there is an internal function IsAnonymousFunctionDefinition()used to determine whether a function is an anonymous function, but this function is only used in the specification, and can not be called by JS code, a lot of JS engine will achieve this function (non-mandatory) internally.

When we talk about anonymous functions, there are actually 2 different meanings:

  1. Function has no name

  2. Function of nameproperty is"anonymous"

Because the function nameis inherited from Function.prototype.name, and therefore function without a name nameattribute is the null character "".

In most debugging tools, functions without names will be displayed as <anonymous>anonymous functions.

Let's rewrite the code in the title:

var a = () => () => { throw new Error('foo') }

Either a()(), or var b = a(); b(), execute in Chrome:

It can be clearly seen that this function is an anonymous function. (Ignore the bottom anonymous function, which is Global Scope)

The call stack in FireFox is:

This is so fascinating. Regardless of how to call ba function, ashould not appear in the call stack, I think this should be regarded as a bug FireFox of the.

If you use a new Functioncustom function, the stack is not wrong angle brackets. Because according to the specification, use the Functiondefined function that has a name, the name is "anonymous". It's like a person called Anonymous, not because he doesn't have a name, but because his surname is Wuming.

In dealing with this, Firefox is slightly better:

var a = new Function('throw new Error("bar")')
a()

FireFox screenshot:

Let's look at Chrome Devtools again:

I'm a little confused, maybe the call stack inside the engine is dumped. I think this can also be considered a bug.

The main problem of wondering, why var a = () => () => 1the function name a, and var b = a()is the anonymous function.

The simple explanation is that it var a = () => 1contains 2 stages, arrow function definition and assignment operation. All functions are anonymous functions arrow, arrows in the definition of the function, the internal specification of hasNameattributes for directly false. Then IsAnonymousFunctionDefinition(expr)determine the function is an anonymous function:

  • If IsFunctionDefinition of expr is false, return false.

  • Let hasName be HasName of expr.

  • If hasName is true, return false.

  • Return true.

When assigning, it will first determine whether the rvalue is an anonymous function. If so, reset the function name.

Let us look at another statement: var b = a(). This also includes assignment operations and a function call operation.

Only when an anonymous function (static semantics) performs an assignment operation, will the variable (rval) reset the name attribute, that is, the function name. Here a() is just a function call, not a function definition, so the function name will not be reset.

akin:

var a = (1, () => 'foo')
a = [() => 1][0]
var a = eval('()=>1')

All are anonymous functions.

Guess you like

Origin blog.csdn.net/vCa54Lu0KV27w8ZZBd/article/details/105479429