all these code snippets run in nodejs.
below are demo1.js, ps: run these code in nodejs rather than browser js engine
// demo1.js
var1 = 'var1'; // in nodejs or Chrome-V8 js engine, this line would create a property named var1 into globalThis/this/window obj
console.log("[globalThis.var1]:", globalThis.var1); // var1
globalThis.var2 = 'var2';
console.log('[var2]:', var2); // var2
var var3 = 'var3'; // in nodejs, this line would not create a property named var3 into globalThis
console.log("[globalThis.var3]:", globalThis.var3); // undefined
function baz() {
var var4 = 'var4'; // in nodejs, this line would not create a property named var4 into globalThis
console.log('[globalThis.var4]:', globalThis.var4);
}
baz(); // undefined
(function () {
var var5 = 'var5'; // in nodejs, this line would not create a property named var5 into globalThis
console.log('[globalThis.var5]:', globalThis.var5);
})(); // undefined
I can understand every thing in demo1.js.
below are demo2.js, ps: run these code in nodejs rather than browser js engine
// demo2.js
(function() {
(0, eval)("var foo = 123;"); (0, eval)("var foo = 123;"); // indirect call eval,create a property named foo into globalThis, which means create a global scope variable foo.
(0, function() { console.log('[globalThis.foo]:', globalThis.foo); })();
})();
console.log('[globalThis.foo]:', globalThis.foo); // 123
console.log('[foo]:', foo); // 123
In demo2.js, I do konw the comma operator would change the eval execution scope to global scope, and also according to Direct and indirect eval – MDN page:
screenshot from MDN eval
My question is:
demo1.js the function baz code block var var4 = 'var4'
or the IIFE code block var var5 = 'var5'
, in nodejs these two line would NOT create a property into globalThis.
But demo2.js the IIFE code block, var foo = 123
, in nodejs this line create a property into globalThis.
In both demo1.js and demo2.js, since variables are declared using the var keyword(like var var4
and var var5
in demo1.js, var foo
in demo2.js), why is only the var declaration in demo2.js create a property into globalThis?
2
Answers
Variable Declarations with var:
When you define a variable with var in a normal function or block, this variable becomes comprehensive in that function or block. That is, it does not appear in the global scope or in globalThis.
Direct and Indirect eval:
demo2.in the js file, the line (0, eval)("var foo = 123;") uses an indirect call of the eval function. In JavaScript, when the eval function is called indirectly, it executes its code in a global scope.
In particular, the indirect eval call causes the foon to be added to globalThis.
Function Scope demo1.For js:
demo1.in the js file, both the base() function and IIFE do not use the eval or comma operator directly. Therefore, the variables defined by var (var4 and var5) remain specific to those functions and are not added to globalThis.
Summary of Differences
demo1.For js:
var4 and var5 remain local and are not added to globalThis because they are defined in function scopes (either in a named function or in IIFE).
demo2.For js:
since the eval function is called indirectly by (0, eval)("var foo = 123;"), foo defined in the global scope. This is a unique behavior of indirect eval.
So, the crux of your question is about the difference in execution context due to how eval is invoked. The use of the comma operator and indirect eval causes foo to be created in the global scope, while the direct variable declarations in demo1.js remain scoped to their respective functions.
NodeJS will automatically wrap your file’s code in a function if you’re using CommonJS (by default, if your package.json lacks a
type
, it’ll be treated a commonjs by default):So, to explain why demo1 works the way it does:
Any variables declared without
var
such asvar1
are automatically made global and become properties of the global object, hence why you can see it onglobalThis
.top-level
var
declared variables such asvar3
would normally also appear on the global object, but since node wraps your code in a function shown above, thevar
is now function-scoped. Anyvar
declared inside a function belongs to that function’s scope; it is not global. Hence, whyvar3
doesn’t actually get added toglobalThis
(but does in your browser console)var4
andvar5
are both declared asvar
inside of functions, so these variables are function-scoped and not global, and so don’t get added toglobalThis
.The important part is the second dot-point, as
var3
doesn’t actually sit in the top-level global scope, it’s not added to the global object. Now indemo2.js
, as you’re using indirecteval
the below line of codeis able to escape the wrapper function Node normally adds, and is now ran in the global scope. As
var
declared variables in the global scope become properties of the global object, you’re able to see it when loggingglobalThis
.