Rohit Banga
Rohit Banga

Reputation: 18918

Understanding the output of this javascript code

Having programmed in C/C++, Java I am finding difficulty understanding the output of the following program.

http://jsfiddle.net/iamrohitbanga/nubgw/

var foo = function() {}
foo.prototype.out = function() {
    console.log(this.num);
}
var bar = function() {};

var f = new foo();
f.num = 1;
var b = new bar();
b.num = 2;

console.log(this);           // 1
f.out();                     // 2
foo.prototype.out.call(b);   // 3
foo.prototype.out.call(bar); // 4

I see the following output

Window
1
2
undefined

I have been coding in javascript for a while now and can understanding some of the concepts but not everything is clear to me.

I have a rough understanding. I feel in the global space this points to the window and hence the first line of output is clear. For the second line I think since the function out is being invoked on f the value of this in out is f. For the third one my feeling is that by calling the function with input as b, the value of -this is set to b. For the fourth one bar is a global object which has no member named 'num' in its dictionary.

Is my understanding correct? Can someone explain the role of 'this' and 'prototype' in the context of this program? I find the syntax of prototype slightly obscure. Also in chrome when I press F12 while in gmail window and paste the program in there. The third line of output is undefined and not 2. But in jsfiddle it is two. which seems somewhat creepy. Why is it different?

Upvotes: -1

Views: 115

Answers (3)

Andres Gallo
Andres Gallo

Reputation: 681

this refers the to the current scope.

With that said, step by step this is why you are getting the results you are getting

var foo = function() {}
foo.prototype.out = function() {//f.out inherits this and so prints 1
    console.log(this.num);
}
var bar = function() {};

var f = new foo();
f.num = 1;
var b = new bar();
b.num = 2;

console.log(this);           
 /* At this point you are making the above log call, outside of any local scope.
 in the global scope =this= refers to =window= */

f.out();
 /* In here the keyword =this= refers to the object =f=
 If we look above it says f.num is 1, so the inherited function which outputs 
 the =num= property then outputs 1.*/


foo.prototype.out.call(b);
/*by adding the call method you are assigning the this keyword to the b object, and
since b.num is 2, just as in the previous step that is being output*/

foo.prototype.out.call(bar); // 4
/*This returns undefined because as in all previous steps, inside the =out= 
function we are printing object.num.  The bar object, however, does not have 
this value*/

I have put explanations as comments in the code. As for the strange behavior in gmail, it is possible that since these are all in the global scope, something is being overwritten by the code already in gmail. Here is a closure that should prevent the above from happening. The first log, will change as this will no longer refer to the global scope

(function(){

   var foo = function() {}
   foo.prototype.out = function() {
       console.log(this.num);
   }
   var bar = function() {};

   var f = new foo();
   f.num = 1;
   var b = new bar();
   b.num = 2;

   console.log(this);           // 1
   f.out();                     // 2
   foo.prototype.out.call(b);   // 3
   foo.prototype.out.call(bar); // 4

})();

Upvotes: 1

MicronXD
MicronXD

Reputation: 2220


console.log(this)

Your assumption is correct. Your program is running at the global scope which in the browser is window.


f.out();

The concept of a prototype is something I'm not sure exists in C/C++ or Java. Essentially, the prototype of an object's constructor is something the object can inherit from. Adding a function to foo's prototype makes it available to all instances of foos.

In this case, earlier in the program, you created an instance of foo called f. Then, you set a property of f called num to 1.

out, a function available to f by extension of foo's prototype console.logs the num property of the object whose context it's being called (in this case, f).

Thus, f.out(); prints 1.


foo.prototype.out.call(b);

call is a function on the Function object's prototype. call calls a function in the context of the first argument. Essentially, this line (foo.prototype.out.call(b);) is identical to doing b.out(); as b is being passed as the context argument.

The rest of the explanation for this line's output is identical to the entirety of the last line's explanation


foo.prototype.out.call(bar);

In this last line, you're calling out on bar. bar is a Function object. bar has no num property thus bar.num is undefined.

This isn't to say you can't add a property to bar the same way you did with f and b. Functions are objects too. So, you can add a property to bar the exact same way it was done to f and b. Adding bar.num = 3 would yield exactly what you're thinking it will yield. Or at least what I hope you're thinking it will...

Upvotes: 2

Starx
Starx

Reputation: 78981

this represents the scope from where the code is executing. In your case, it is the global scope window.

Prototypes in JavaScript are simply an object with properties and methods. You can add members to it and also inherit from it. You can read this article for further information.

Lets break down your code are see this one by one.

  1. f.out();

    This refers too the following object

    var f = new foo();
    f.num = 1; //Here you define a property `num` as 1
    

    Then when you call f.out() the prototyped function will simple log the num

  2. foo.prototype.out.call(b);

    Here you directly access the function and pass an object to the function. Thus when the method is executed, this represents the object that is pass instead, so ends up logging its value.

  3. foo.prototype.out.call(bar);

    On this part, the object bar is an empty object var bar = function() {};, thus the function cannot read its num property, so it outputs as undefined

Upvotes: 1

Related Questions