Javascript closure not working as expected - javascript

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.

Related

Immediately Invoked functions in javascript

I have a clarification in using IIFs in javascript .
I have downloaded a javascript file called called test.js as follows and I have got following questions after googling IIFs:
define(function () {
(function (window) {
this.test = function() {};
Test.prototype.function1 = function(){
//Do something
},
function Delete(){
//Code to Delete
}
window.Delete = Delete;
})(window);
});
I do have the following questions:
Is the line,
this.test = function() {}; a constructor?
If so can I have 2 constructors in a single file like for example:
this.test = function() {};
this.test2 = function() {};
And also, why would I need a constructor when I know that this is an automatically invoked file where everything gets executed initially itself.
Is this a private function?
Test.prototype.function1 = function(){
//Do something
},
Does this not get automatically? Should I need to create an object of the test and then invoke it?
Is this a public function?
function Delete(){
//Code to Delete
}
window.Delete = Delete;
The last line of the above says that . If it is so then whats the difference between first and second function?
What is keyword window here?
It's worth noting that this code will fail with an error, as Test is undefined, and you can't set the prototype property on undefined.
In JavaScript, any function can be a constructor. It's up to how you use it. You can add functions and properties to the .prototype property of any function, and any objects created from it using new will get them from the prototype chain. In your case, this.test = function(){} doesn't look like a prototype.
There's no such things a "public" or "private" functions in JavaScript, there's only what's exposed via return out of the function (or in your case, by using the global window object, which is considered bad practice) If the Test function is exposed somewhere, then Test.prototype.function1 is also exposed. All prototype methods are "public".
Yes, sort of. Like I said, "public" or "private" isn't a thing in JavaScript. You created a function and placed it on the window object, which is global. Essentially, you've made the function global.
window is the global browser object. Although when used like this (function(window) { ... })(window), the first window is the name of the parameter, (and any instances of window inside the function reference to that parameter, and the second one (passed to the function call), is the global window object.
Further reading:
The Revealing Module Pattern

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

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?

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();

"this" keyword in a javascript module

I have defined the following module globally:
var module = (function () {
console.log(this);
this.fn = function () {
console.log(this);
}
return this;
})();
http://www.quirksmode.org/js/this.html :
In JavaScript |this| always refers to the “owner” of the function we're executing, or rather, to the object that a function is a method of.
The first call to console.log logs Window as the value of this, and that I understand. But, so does also the second call to console.log.
Since this refers to the owner of the function, why does module.fn log Window and not module?
When I call fn I still have to write module.fn, I can't write Window.fn. Since this refers to Window I find this confusing.
EDIT: I forgot to return this in my example.
Since this refers to the owner of the function, why does module.fn log Window and not module?
The return value of the outer function is window because it doesn't get called in any particular context, so module ends up being window as well.
It seems that the way you have applied the module pattern is wrong. It should be returning the public interface that gets used in the rest of your code:
var module = (function () {
console.log(this);
// public interface
return {
fn: function () {
console.log(this);
}
}
})();
module.fn(); // "Object {fn: function}"
In your example, the global object receives the fn. It is the window object in case of browsers. That is because you are calling the function in place (effectively constructing a new scope) without specific context.
On the end, your module object is just a reference to the window (because of return this;).
What is this?
In JavaScript, this is the current context, the object on which the function was called that particular time. It is not the "holder" of the function. You can always "steal" the method from other objects and apply (literally) it to your own.
Assume you want to slice the arguments object for some reason. It looks just like an array, but it is NOT an array. arguments.slice(2,4) does not work (assuming ECMAScript < 5). What to do?
Array.prototype.slice.apply(arguments, [2,4]);
You need to steal the slice function from the Array prototype, and use if on your arguments. Inside the slice call, the "this" is the arguments object that particular time.
How to construct a valid module?
Your job is to return the module object. You do not want do mess with the context. It is not relevant, as long as you are not applying the function directly on module object.
The easiest solution is the simplest.
var module = (function() {
// do something internally, great for "private" stuff
// then return the "public" interface
return {
doSomething: function() {
// do something
},
introduce: function() {
console.log(this);
}
};
})();
module.introduce(); // Object {doSomething: function, introduce: function}
module.doSomething();
The other way.
Alternatively, you could use the this to do your job, using the apply, if you really want to.
var module = {};
(function(){
this.doSomething = function() {
// do something
};
this.introduce = function() {
console.log(this);
};
}).apply(module);
module.introduce(); // Object {doSomething: function, introduce: function}
module.doSomething();
Note this is almost equal to the "new" call.
There are more equally valid ways to do it, but the first presented one is frequently used and very clear. Anyway, everything really depends on your code conventions.
Your pattern is wrong what you are doing to make a closed scope and setting module to the return from that scope:
// This is the design pattern:
var module = (function () {
var module = {};
var localVar = 1;
module.moduleVar = 2;
module.fn = function () {
console.log(this);
}
return module;
})();
console.log(module.fn); // function() { console.log(this) ;}
console.log(module.moduleVar); // 2
console.log(module.localVar); // undefined

javascript how to get this.variable in callback function

In the following customized class in javascript, in callback, why does this.obj have nothing but local variable obj has thing I want? Thanks.
function ClassTest(director) {
this.obj = {"test1": "test1"};
}
function test1(input, callback) {
callback("success");
}
ClassTest.prototype.test = function() {
var obj = this.obj;
test1("niuniu",function(e){
console.log(this.obj); // undefined
console.log(obj); // this one has stuff
});
}
// run
new ClassTest().test()
Because the function inside test1 is creating a new scope with different this context. Typical solutions are to bind or to cache this:
Binding:
test1("niuniu",function(e){
console.log(this.obj);
}.bind(this));
Caching:
var self = this;
test1("niuniu",function(e){
console.log(self.obj);
});
As for this line of code:
console.log(obj); // this one has stuff
The reason it works has to do with how JavaScript closure works. The code defined in your anonymous function has access to all variables in its local scope as well as variables defined in encompassing scopes and therefore obj is available. See How do JavaScript closures work? for more on closure.
The keyword this however, is a reference to the current scope. Because you are accessing this.obj from within the anonymous function, this refers to the anonymous function itself - which has no obj property defined. In the enclosing function, which is extending the ClassTest prototype, this refers to the current ClassTest object, which does have a obj property defined.

Categories