Differences between Node.js and Node.js REPL [duplicate] - javascript

This question already has answers here:
In what scope are module variables stored in node.js?
(4 answers)
Closed 4 years ago.
I'm reading the "You don't know JS" book series and I tried to run the snippet:
function foo() {
console.log( this.a );
}
function doFoo(fn) {
// `fn` is just another reference to `foo`
fn(); // <-- call-site!
}
var obj = {
a: 2,
foo: foo
};
var a = "oops, global"; // `a` also property on global object
doFoo( obj.foo ); // "oops, global"
(You can find it in the 2nd chapter of the 3d book: 'this' All make sense now)
If I save this into 'foo.js' and run it with node foo.js (v 8.11.1) then I get undefined. While if I start node REPL and type in the same code I get:
> function foo() { console.log(this.a); }
undefined
> function doFoo(fn) { fn(); }
undefined
> var obj = { a:2, foo:foo };
undefined
> var a = "oops, global";
undefined
> doFoo(obj.foo);
oops, global
undefined
As expected from the book.
Same result on Firefox dev console.
If I remove the declaration and leave only the assignment a = "oops, global" then it run as expected both on REPL and Node.js. This make more sense to me because in this way I'm setting a property on the global object, while in the "original" way I'm just declaring a variable.
Can anyone explain to me this behaviour? Thank you all.
EDIT: I think I'm close to the solution, I noticed that if I make a script foo.js that contains only:
var x = 42;
console.log(this);
I get {}, so x is not attached to the global object. While if I start the Node.js REPL and type in the same code I get a big object with x attached to it:
{
...
x: 42
}
So I think the difference it depends on "who is the global object?" in REPL and in Node.js.

When you run the file in Node.js, your var a isn't actually in global scope, but function scope -- a module function scope (more on this here). Basically all of the contents of the file is run as if inside a function. So var a is actually in that function scope.
Whereas in REPL it's truly in global scope.

Related

What is the default scope in Node.js application? [duplicate]

When I do this in my node.js module:
var abc = '123';
Where does it go? And by this I mean: in the browser it goes in window.abc (if not executed in a function or otherwise)
If I execute this:
abc = '123';
Then I can find it in global.abc, but that's not how I want it.
Unlike the browser, where variables are by default assigned to the global space (i.e. window), in Node variables are scoped to the module (the file) unless you explicitly assign them to module.exports.
In fact, when you run node myfile.js or require('somefile.js') the code in your file is wrapped as follow:
(function (exports, require, module, __filename, __dirname) {
// your code is here
});
All the other answers are 100% correct, but I thought I would add an expanded/definitive list of the scopes within a Node.js application in case anybody comes across this via Google while starting off learning Node.js or JavaScript:
Global Scope
Anything declared without the var keyword in any file will be accessible from anywhere running in the same instance of the Node server:
// foo.js
bar = 'baz';
// qux.js
console.log(bar); // prints 'baz'
Note that this is widely considered to be a bad idea, because it makes your app strongly 'coupled'– meaning that you'd have to open foo.js to work out why bar = 'baz' in qux.js
Module Scope
Anything declared with the var keyword at the top level (not inside a function or object, or any other block) of a node.js file is in module scope, and will be accessible from anywhere within the same file, but will not exist anywhere else:
// foo.js
var bar = 'baz';
console.log(bar); // prints 'baz'
// qux.js
console.log(bar); // prints 'undefined'
Function Scope
Anything declared using the var keyword within a function will only be accessible from within that function, and not from anywhere else:
// foo.js
function myFunction() {
var bar = 'baz';
console.log(bar); // prints 'baz'
}
function myOtherFunction() {
console.log(bar); // prints 'undefined'
}
// qux.js
console.log(bar); // prints 'undefined'
JavaScript is function scoped. Unlike other (block scoped) languages, variables declared in a block within a function are accessible from anywhere else in that parent function. For example, this means that if you declare a new variable inside inside a loop, it's accessible outside of that loop as well, as long as you're still inside the parent function:
function myFunction() {
while (thing === true) {
var bar = 'baz';
thing = false;
}
console.log(bar); // prints 'baz'
}
Shadowing
If you 'redeclare' an existing variable, e.g. use the var keyword with a variable name that has been used already, then the value associated with that variable name is overwritten within the scope of the new declaration:
var bar = 'foo';
console.log(bar) // prints 'foo'
function myFunction() {
var bar = 'baz';
console.log(bar);
}
myFunction(); // prints 'baz'
console.log(bar) // prints 'foo'
Node has a module scope, so var abc = '123' in a module will create a variable which is scoped to (and therefore, reachable only for code in) that module.
See also http://nodejs.org/api/globals.html#globals_global
Pretty old question, and if anyone is curious about ECMA specs about this question, here is the link
And there is no way for direct access for module variables (except for imported modules):
Lexical Environments and Environment Record values are purely specification mechanisms and need not correspond to any specific artefact of an ECMAScript implementation. It is impossible for an ECMAScript program to directly access or manipulate such values.

Use of var in the global namespace

I'm reading "you don't know javascript" and I find some trouble with one example in the book "This & Object Prototypes".
When discussing the different rules for this, specifically in the "Implicit binding" paragraph, the author gives this example:
function foo() {
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo; // function reference/alias!
var a = "oops, global"; // `a` also property on global object
bar(); // "oops, global"
However when trying this on JSFiddle I get an undefined output in console instead of the "oops, global".
Conversely, if I define a without var or using window.a I get the output intended by the author regardless of strict mode.
Why is this happening? Did something in ES6 change the way global variables should be declared?
The default settings for JS Fiddle wrap the JS in a function and assign it as an load event handler.
Your tests are not in the global scope.

why there are differences for below code runing in browser and nodeJS?

I have below code which I expect the results would be printing 2, 2.
When I run it in nodeJS console, I got undefined, undefined.
When I run it in Chrome, I got expected values.
My questions, what differences make this result?
var a = 2;
function foo(){
console.log(this.a);
}
(function(){
foo();
}())
function doFoo(fn){
fn();
}
var obj ={
a:3,
foo:foo
};
doFoo(obj.foo);
Node.js does not execute code in global scope. Instead each file is wrapped in an IIFE so that each file get their own scope. The difference therefore is that in the browser, var a = 2 is a global variable whereas in node.js var a = 2 is not a global variable.
Since your code prints the global variable a, in the browser that would be 2. In node.js you have not defined a therefore it prints undefined.
To make the code the same change var a = 2 to a = 2 in order to declare a global variable instead of a local variable.

Why this strange behavior? [duplicate]

This question already has answers here:
Why is my global variable shadowed before the local declaration?
(3 answers)
Closed 9 years ago.
I'm modifying a piece of code in 3 ways. In these 3 conditions in is behaving differently. Please describe how it's executing?
var a=1;
function myFunc(){
console.log(a);
console.log(a)
}
myFunc();
//Output is:
1
1
var a=1;
function myFunc(){
console.log(a);
var a=2;
console.log(a)
}
myFunc();
//Output is:
undefined
2
var a=1;
function myFunc(){
console.log(a);
var a=2;
console.log(a)
}
myFunc(a);
//Output is:
undefined
2
Why in 2nd case it's printing undefined? And in 3rd case I'm sending my global a as an argument, then also it's printing undefined.
That's because JavaScript moves var declarations to the top of the scope, so your code actually is:
var a = 1;
function myFunc(){
var a; // a is redeclared, but no value is assigned
console.log(a); // therefore it evaluates to undefined
a = 2; // now a = 2
console.log(a); // and then it logs to 2
}
myFunc();
This behaviour is called Variable Hoisting.
EDIT
As Beterraba said, in the third code it logs undefined because no argument was declared in the function's header:
var a = 1;
function myFunc(a) { // a is declared
console.log(a); // now a logs 1
var a = 2; // now a = 2
console.log(a);
}
myFunc(a);
The second case is printing undefined due to the way that JavaScript Execution context works. You might have come across the term hoisting.
To explain it in more details, when the second function is invoked, the interpreter will enter a process with two phases.
Creation stage
Creates the scope chain
Creates arguments, functions, variables, the so-called variable object
Determines the value of "this" keyword
Activation or code execution stage
interprets and executes the code
So when you callmyFunc() the JavaScript interpreter will create an execution context which you can think of as an object literal that looks like this:
myFuncExecutionContext = {
scopeChain: { ... },
variableObject: {
arguments: {
length: 0
},
a: undefined,
},
this: { ... }
}
You can see that the local a variable has an initial value of undefined. During the code execution stage, the interpreter will run the function line by line; So the first line it sees is the console.log(a);. The interpreter will look at the variableObject to see if there is variable with that name. If not it will use the scope chain and will try to locate it in the variable object of the outer scopes. Since, there is the a variable in the variable object, it will read it's value, which is undefined.
Then it will do to line 2 where it will assign a value to the local variable a; var a=2;. Then it will execute the last line - console.log(a) - which will print the value that we assigned earlier.
The same mechanism justifies why we can invoke a function before it's defined, as long as, we use a function declaration syntax.
someFunc(); // VALID
function someFunc(){ };
Whereas the following will cause an error:
someFunc(); // TypeError: undefined is not a function
var someFunc = function() { }

fn.call(this) versus fn() when defining a CommonJS module

It's common to see CommonJS modules defined using the following idiom:
(function() {
var logThis = function() { console.log(this); }
module.exports = logThis;
}).call(this);
Underscore.js, for example, does this.
I just spend half an hour discussing with a colleague why they invoke the closure with call(this). This will cause the value of this inside the closure to be inherited from the caller, rather than being set to the global object. However, when I tested this in Node.js, the value of this inside the module was always the global object, even when I loaded and ran it like this:
var bar = {};
bar.foo = function() { var foo = require("./foo"); foo(); }
I was really expecting to see the bar object in the console, but actually I see the global object. It then occurred to me that this might be because modules like Underscore.js are also used in a web context. But in that case it would be loaded with a <script> tag so this will always be equal to the global object anyway.
What gives? I'm sure there is a reason for using this construct but I can't see the practical difference in this particular case whether the module is being used in Node.js or in a webpage.
Update: Just to clarify, I can think of a number of cases where this could make a difference. For example, if I say:
var bar = {}
var foo = require("./foo");
bar.foo = foo;
bar.foo();
(Thanks to #Pointy for correcting my original example.)
I would expect the closure in the module to be evaluated when require() is called, which means that the value of this inside it would be bound to the global object, which would be written to the console even though foo() is then invoked as a member of the "bar" object. However, I am seeing the "bar" object in the console even in this example. I guess that this is not being bound to the closure as I expected?
In a nutshell, I'm looking for one example where a module like Underscore.js will have different behavior due to being wrapped in a closure invoked with fn.call(this) instead of just fn(), either in Node.js or in a web page.
Your call to "foo" inside "bar.foo" is made without any context, so the global context is used. The fact that it's inside a function where this refers to "bar" is not relevant; that's just not how JavaScript works. The only thing that matters is how the function is invoked, not where it's invoked, in other words.
If "bar.foo" looked like this:
bar.foo = function() { require("./foo"); foo.call(this); }
then you'd see "bar" in the console. Or, you could do this:
var bar = {};
require("./foo");
bar.foo = foo;
Then calling bar.foo() would also log the "bar" object. (Does that really work in Node? That is, I thought require() returned an object, and that it didn't just leave things in the global scope. I'm a rank novice at Node however.)
edit — OK thanks for updating. Thus, my example would be corrected as follows. First, I think that your module should look like this:
(function() {
var logThis = function() { console.log(this); }
module.exports.logThis = logThis;
}).call(this);
That is, I think that you want to explort the "logThis" function, so it needs to be bound to the "exports" object as a named property.
Then:
var bar = {};
var foo = require("./foo");
// At this point, foo.logThis is the function
bar.foo = foo.logThis;
// Now the "foo" property of "bar" is a reference to the same function
bar.foo(); // logs the "bar" object
var fee = { fie: foo.logThis };
fee.fie(); // logs the "fee" object

Categories

Resources