Default binding of `this` is different from Chrome browser and Node.js - javascript

I was reading Chapter 2: this All Makes Sense Now! from You Don't Know JS, and decided to do this experiment.
I have this simple enough script foo.js:
var a = 'foo';
var output;
// lets find a way to output strings in both
// Chrome and Node.js
if (typeof alert === 'undefined') {
output = console.log;
} else {
output = alert;
}
function getA() {
return this.a;
}
var foo = getA();
output(foo);
I am expecting following things when getA() is called:
Since the call site of getA is in global scope, getA() will be bound to global object.
Since var a is declared in global scope, I take it that global object will have a property named a, and this property is same as the variable a.
Because of that, I expect this.a to refer to variable a.
Thus I expect output(foo) to print the string foo.
However, when run in Node.js (non-strict mode), this is the output:
$ node foo.js
undefined
Then I included the same script in a simple HTML page, and loaded it in chrome.
<html>
<head>
<script src="foo.js" type="text/javascript"></script>
</head>
<body>
</body>
</html>
Chrome alerts the string foo, just as expected.
Why does the output of Chrome differ from Node.js?

Since the call site of getA is in global scope, getA() will be bound to global object.
This is a misunderstanding of the this binding rules from my book. The call site's location (aka "in global scope") is entirely irrelevant. It's the manner in which the call is made, and only that.
It's not where getA() happens that matters, but that getA() is a plain normal function call. THAT is what determines that you'll get the global object bound to the this for that call.
The other answers here are correct... the scope your node main program runs in is actually a module (function wrapped), not a real global scope.

Since the call site of getA is in global scope, getA() will be bound to global object.
no, that's not true for node - your script is wrapped into a function here so your example is actually this code:
(function (exports, require, module, __filename, __dirname) {
var a = 'foo';
var output;
// lets find a way to output strings in both
// Chrome and Node.js
if (typeof alert === 'undefined') {
output = console.log;
} else {
output = alert;
}
function getA() {
return this.a;
}
var foo = getA();
output(foo);
})(exports, require, module, 'file.js', '/dir/name');

NodeJS behaves differently than browsers. The top-level scope is not the global scope, it's the scope within that file or module. Drop the "var" and your code will work (a will become truly global) in a node environment and it will console.log the string 'foo'.
See the following page for a full reference: http://nodejs.org/api/globals.html
OR
How to use global variable in node.js?

Related

Redefinition of variable in node.js

The execution of this script: tmp.js, that contains:
var parameters = {};
(1,eval)("var parameters = {a:1}");
(1,eval)(console.log(parameters));
node tmp.js
produces:
{}
If we comment out the first statement, and execute again the script, we obtain:
{ a: 1 }
The global scope contains exactly the same variables with the same value, so why console.log displays a different value?
Because all code you run in Node is running in a Node module,¹ with its own scope, not at global scope. But the way you're calling eval (indirectly, (1,eval)(...)) runs the code in the string at global scope. So you have two parameters variables: A local one in the module, and a global one. The local one wins (when it exists).
var parameters = {}; // <== Creates a local variable in the module
(1,eval)("var parameters = {a:1}"); // <== Creates a global variable
(1,eval)(console.log(parameters)); // <== Shows the local if there is one,
// the global if not
Your last line of code is a bit odd: It calls console.log, passing in parameters, and then passes the return value (which will be undefined) into eval. Not much point in that call to eval with undefined.
If that last line were
(1,eval)("console.log(parameters)");
...it would run at global scope, not module scope, and always show the global.
Here's an example that does the same thing without Node:
(function() {
var parameters = {};
(1,eval)("var parameters = {a:1}");
console.log("local", parameters);
(1,eval)('console.log("global", parameters);');
})();
¹ FWIW, according to the documentation, your code is wrapped in a function that looks like this:
(function(exports, require, module, __filename, __dirname) {
// Module code actually lives in here
});
...and then executed by Node.

Javascript closure not working as expected

I'm running this code on nodejs. I was wondering why the closure when executed does not print the string 'Globals'? Isn't the this in the closure pointing to the global scope?
// Running on NodeJS, not in a browser!
this.name = "Globals";
function Person(name) {
this.name = name;
this.namePrinter = function() {
return function() {
console.log(this.name);
}
}
}
var p = new Person("Faiz");
p.namePrinter()(); // prints undefined. Shouldn't it print Globals?
console.log(this.name); // prints Globals
Your example works as intended in a browser, but in node.js this on the top level is not the same as global, it's your module .exports. So when you do
this.name = "Globals";
It assigns name: Globals to module.exports, not to the global object.
Now, when you write
p.namePrinter()();
it's the same as:
func = p.namePrinter();
func();
The function is unbound (= there's no object. before it), so its this will be the global object. But there's no name there...
In browsers, your top level code is executed in the context of the global object (which is window) and this is the same object unbound functions use. That's why your snippet works.

Difference Between Node.js and JavaScript Context [duplicate]

When I type this in node.js, I get undefined.
var testContext = 15;
function testFunction() {
console.log(this.testContext);
}
testFunction();
=>undefined
Without var keyword, it passes (=>15). It's working in the Chrome console (with and without var keyword).
It doesn't work in Node when using var because testContext is a local of the current module. You should reference it directly: console.log(testContext);.
When you don't type var, what happens is that testContext is now a global var in the entire Node process.
In Chrome (or any other browser - well, I'm unsure about oldIE...), it doesn't matter if you use var or not in your example, testContext will go to the global context, which is window.
By the way, the "global context" is the default this of function calls in JS.
The key difference is that all modules (script files) in Node.js are executed in their own closure while Chrome and other browsers execute all script files directly within the global scope.
This is mentioned in the Globals documentation:
Some of these objects aren't actually in the global scope but in the module scope - this will be noted.
The vars you declare in a Node module will be isolated to one of these closures, which is why you have to export members for other modules to reach them.
Though, when calling a function without a specific context, it will normally be defaulted to the global object -- which is conveniently called global in Node.
function testFunction() {
return this;
}
console.log(testFunction() === global); // true
And, without the var to declare it, testContext will default to being defined as a global.
testContext = 15;
console.log(global.testContext); // 15
As mentioned in the document
var something inside an Node.js module will be local to that module.
So, it is going to be different as the var testContext is in module context and the context of this is global.
You can alternatively, use:
global.testContext = 15;
function testFunction() {
console.log(this.testContext);
}
testFunction();
I believe the problem has to do with the this key word. If you do console.log(this) you will see that testContext is not defined. You may want to try:
this.testContext = 15;
function testFunction() {
console.log(this.testContext);
}
testFunction();

How to call/use this module in other JS files/modules

I read some JS module design patterns recently. I came across this small code snippet as below.
(function(window) {
var Module = {
data: "I'm happy now!"
};
window.Module = Module;
})(window);
Still not quite understand this code well, my questions are:
How to use/call this module outside this particluar JS file? Need I
assign a variable to this module? e.g. var module1 = (...)(...);
Could anyone explain what the window parameter here stands for?
Is it a good practice to have two/three such kind of modules in the
same file?
The main reason to create an anonymous function in this case is to prevent global object pollution. It's not really a module pattern.
The problem arise when you declare a variable. Without the function scope, the variable will be added to the global object (window). If you were to declare the variables within a function. It would add the variable to the function scope without polluting the global object window.
What happen is that a javascript file could add a variable named foo and on a different file use that variable named foo too. Unless you really want to have a variable shared by two javascript files, it would probably create conflicts and bug that are difficult to fix.
For example: a.js
var foo = "one"
b.js
var foo = "two"
c.js
alert(foo)
In this case, the alert box might show either "one" or "two", depending of the order in the javascript files are included.
But having this a.js:
(function () {
var foo = "one"
})()
b.js
(function () {
var foo = "two"
})()
c.js
(function () {
alert(foo)
})()
This would create an error as you cannot alert a non declared variable.
One way to detect undefined variables, is to make sure to execute the javascript code in strict mode.
To do that, add the string "use strict" at the top of the file or function.
function () {
"use strict"
...
}
Undeclared variable will raise errors and it should be possible to fix the code that way.
Also, if you forget to declare a variable with the var keyword, it might end up adding the variable to the global scope even if the code is scoped into a function. The only way to prevent global scope pollution is to run the code in strict mode.
In the code snippet that you provided, the module with name Module is explicitly added to the window object. You can access the window object from any place in javascript unless the window name is ghosted by an other variable.
Now, back to the modules. If you want to define modules, it can be done in many ways. As an exemple, you could create an object on the window object called modules. In this object, you'll insert your modules.
module.js
window.modules = {}
foo.js
(function (window) {
var module = {}
...
window.modules.foo = module
})(window)
This variant isn't super good as you have to manually add the module to the modules object. You have to manually modify the window object, and that can be subject to errors.
modules.js
window.modules = {}
function define(name, constructor) {
var module = {exports: {}}
constructor(module)
window.modules[name] = module.exports
}
function require(name) {
return window.modules[name]
}
foo.js
define("foo", function (module) {
module.exports.one = function () {
return 1
}
module.exports.plus = function (a, b) {
return a + b
}
})
bar.js
define("bar", function (module) {
module.exports = function () {
var foo = require("foo")
return foo.plus(foo.one(), foo.one())
}
})
This is a module definition that looks a bit like module defined with http://requirejs.org/. It is quite basic as it doesn't take into account module dependencies so if bar is loaded and used before foo. Then the require method won't be able to return the module.
Also, if you want to store modules without having them visible into the global scope, you can only define the require and define method on the window object and hide modules into an anonymous scope like this:
(function (window) {
var modules = {}
function define(name, constructor) {
var module = {exports: {}}
constructor(module)
modules[name] = module.exports
}
function require(name) {
return modules[name]
}
window.define = define
window.require = require
})(window)
This way, define and require are the only function that can give you access to modules. Other modules won't be able to modify other modules without requiring them first. This can be useful when using third parties script that could conflict with your module system.
In fact this is not a module, but a Self-Invoking Ananymous function or an Immediate function which gets an object in parameter and assign a Module property to it:
The page window is a parameter passed to this function.
So an object named Module containing a data property is assigned to window.
JavaScript Self-Invoking Functions:
A self-invoking expression is invoked (started) automatically, without being called.
Function expressions will execute automatically if the expression is
followed by ().
You cannot self-invoke a function declaration.
You have to add parentheses around the function to indicate that it is
a function expression
So As you can see Immediate Functions can't be called as its name states it will be immediately executed and by its self, no other function or scope can execute it.
For better reference take a look at :
Javascript Self Invoking Functions.
Self-Invoking Functions section in JavaScript Function Definitions.
And concerning your last question about its benefits and good practices as shown on the given Article reference:
Where to use self-executing functions?
One obvious situation is when you want to auto-run a function like I
showed in above example but that is trivial. If you are in a situation
where you want to run a piece of code repeatedly like updating
something in the database based on user interaction or fetching
records from database every 10 seconds or you want to load new stories
via ajax similar to how facebook does on its homepage or some other
similar situation, one would normally go for setInterval function
something like this:
setInterval(doStuff, 10000);
Above, doStuff function will get called every 10 seconds. That is the
normal approach most developers seem to go with. However, there is a
huge problem with that.
The setInterval will call doStuff function exactly at specified time of 10 seconds again and again irrespective
of whether doStuff function actually finished doing what it is
supposed to do. That is bad and will certainly get you into unexpected
results.
That is one example of where setInterval is "bad" and should be
avoided.
This is exactly where self-executing functions come in handy. We can
do the same task with the help of self-executing function along with
setTimeout like this:
function foo(){
// your other code here
setTimeout(foo, 10000);
}();
This code will also repeat itself again and again with one difference.
setTimeout will never get triggered unless doStuff is finished. A much
better approach than using setInterval in this situation.
Calling it from another file:
And if this function is on another file it will be called automatically if this file is included.
Why do we use Self-Invoking Functions in JavaScript?
And if you ask yourself why do we use these functions, self-invoked function are used to manage Variable Scope.
Take a look at the answer here for further information.

Node.js variable declaration and scope

When I type this in node.js, I get undefined.
var testContext = 15;
function testFunction() {
console.log(this.testContext);
}
testFunction();
=>undefined
Without var keyword, it passes (=>15). It's working in the Chrome console (with and without var keyword).
It doesn't work in Node when using var because testContext is a local of the current module. You should reference it directly: console.log(testContext);.
When you don't type var, what happens is that testContext is now a global var in the entire Node process.
In Chrome (or any other browser - well, I'm unsure about oldIE...), it doesn't matter if you use var or not in your example, testContext will go to the global context, which is window.
By the way, the "global context" is the default this of function calls in JS.
The key difference is that all modules (script files) in Node.js are executed in their own closure while Chrome and other browsers execute all script files directly within the global scope.
This is mentioned in the Globals documentation:
Some of these objects aren't actually in the global scope but in the module scope - this will be noted.
The vars you declare in a Node module will be isolated to one of these closures, which is why you have to export members for other modules to reach them.
Though, when calling a function without a specific context, it will normally be defaulted to the global object -- which is conveniently called global in Node.
function testFunction() {
return this;
}
console.log(testFunction() === global); // true
And, without the var to declare it, testContext will default to being defined as a global.
testContext = 15;
console.log(global.testContext); // 15
As mentioned in the document
var something inside an Node.js module will be local to that module.
So, it is going to be different as the var testContext is in module context and the context of this is global.
You can alternatively, use:
global.testContext = 15;
function testFunction() {
console.log(this.testContext);
}
testFunction();
I believe the problem has to do with the this key word. If you do console.log(this) you will see that testContext is not defined. You may want to try:
this.testContext = 15;
function testFunction() {
console.log(this.testContext);
}
testFunction();

Categories