Reputation: 3745
Does an empty function body implicitly return undefined
in JS?
console.log((() => {})())
Clearly it does right? The console outputs undefined
in the example above...
// but let's do something crazy
console.log(((undefined) => undefined)("defined"));
console.log((() => {
var undefined = "defined";
return undefined;
})());
Ok so we can redeclare undefined
locally (or globally without strict mode)
console.log(((undefined) => {
var undefined = "defined_again";
})("defined"));
But the output is still undefined
, so it seems it's not implicitly returning undefined
, but instead treating the entire expression as void(expr)
.
This also seems to be the case in TypeScript:
const result = (() => {})()
// ^?: const result: void
So if the empty function body does implicitly return undefined
as outlined in the spec, then why does JS ignore lexical scope for undefined
if it's redeclared in the function body?
Obviously at the end of the day the result is undefined
, but I'm more curious about the actual implementation behavior of what is implicitly returned?
Does the empty function body actually return something?
Upvotes: 0
Views: 74
Reputation: 916
I hope your snipped #2 is already clear. You introduce the variable undefined
, and it does not reference the global read-only property undefined
. This is just the local variable stored on the stack. As you explicitly return it, the outer stack receives the value 'defined'
, and the variable itself is removed in the sense of popping the stack.
It is important to understand that undefined
is not a global variable or something. There is no such thing. There is the global object globalThis
, everything else can be a property of this object. Of course, this object depends on the environment. For example, in a Web browser, it is referentially the same as window
.
Anyway,
console.log(globalThis.undefined === undefined);
outputs true
, this is the same thing.
The property globalThis.undefined
returns the unique object, its value has a unique primitive type. Importantly, you cannot get information on this type by getting its constructor
(undefined.constructor
will throw an exception): undefined
cannot by dereferenced. However, it is not null
but a distinctly different object. Note that both expressions myObject == null
and myObject == undefined
return true
if myObject
is undefined
or null
, and this is a very convenient thing for practical purposes. And yet, undefined
is not null
, we can see it if we use the operator ===
. The distinction between null
and undefined
is very specific to JavaScript.
Now, all of the above should give you an idea of what happens in snippet #3 with its var undefined = "defined_again"
. Still undefined
, you say? But what is undefined? The variable referencing "defined_again"
is, again, a stack variable, it does not exist after return, and it is totally unrelated to globalThis.undefined
. I hope it should be clear.
The remaining problem is to explain why all functions that don't return anything behave exactly as if they returned globalThis.undefined
. You know, I am not looking at JavaScript implementation and am not sure. I just think the particular mechanism is not so important, and it even may vary. What is important is the apparent functionality. In essence, you are right, this is like the void
. Maybe the compilation of the source code injects the return of globalThis.undefined
in every function, or maybe the void
condition is somehow detected at the level of the calling function. If the returned object is not discarded, it becomes accessible in the calling stack frame and found to reference globalThis.undefined
, and nothing else. And this is all that matters.
const a = () => { };
console.log(a() === globalThis.undefined);
outputs true
.
Upvotes: 1
Reputation: 424
None of these are actually logging the empty function body.
Code 1 console.log((() => {})())
is taking an empty function, executing it, and sending its results (undefined
) to console.log. The same as if you console.log(undefined)
.
Code 2.A is passing the execution of a function that takes a parameter and returns that parameter the same as console.log((foo) => foo)("defined"))
. Having a weird variable name doesn't matter
Code 2.B is really just the same as console.log((()=> "defined")())
. Having a weird variable name still doesn't matter.
Code 3. Essentially the same as 1. You aren't returning anything so console.log is returning undefined
because that is exactly the result of the function execution.
Upvotes: 0
Reputation: 281748
It returns undefined
, as in the specific ECMAScript language value undefined
, not performing a variable lookup for an undefined
variable and returning whatever the lookup returns. If you want to go to the spec, you can see that the rule for a function completing normally without an explicit return
is
- Return ReturnCompletion(undefined).
where a bold undefined in variable-width font means the ECMAscript language value:
In this specification, ECMAScript language values are displayed in bold. Examples include null, true, or "hello". These are distinguished from ECMAScript source text such as
Function.prototype.apply
orlet n = 42;
.
(And yeah, it's a little awkward that ECMAScript source text is also bold.)
Upvotes: 2