2

I am learning javascript. Have two blocks of code in below. As you can see that first one works just fine but second one does not. Different between them is that I use this.count to access the count variable defined in the counter2,

function counter1(start){ 
    var count = start; 
    var increase = function(){
        count++;
    }; 
    var getValue = function(){
       return count;
    };
    return { 
            inc : increase, 
            get :getValue }
}

var c1 = new counter1(5);
c1.inc(); //is able to increase 1
console.log(c1.ge());//can return 6
function counter2(start){ 
    var count = start; 
    var increase = function(){
         this.count++;
    }; 
    var getValue = function(){
         return this.count;
    };
    return { 
    inc : increase , 
    get :getValue }
}

var c2 = new counter2(5);
c2.inc(); //can NOT access this.count
console.log(c2.ge());//return NaN

I am a little confused with the "this" in counter2 as you can see, when I debug the code, "this" is counter2, but just has no access the the count variable
enter image description here

So could you help me to understand why 'this' in counter2 is not have the access to the count variable? and why I can access count variable in the increase function in counter1 even if I did not use "this". Does this makes the code "worse" (less accessible)?

Thanks

Cerbrus
  • 70,800
  • 18
  • 132
  • 147
Xavier
  • 389
  • 7
  • 20
  • May it have anything to do with `var ___ = function() vs function ___()`? I know very little about the difference between them. – ndugger May 27 '14 at 14:11
  • That's because `count` is a closure variable, if you want it to be an instance variable instead - do `return { count:0,/*everything else*/` alternatively, you can access it with `count` without `this.` since it's closed over. – Benjamin Gruenbaum May 27 '14 at 14:11
  • @NickDugger no, it does not have anything to do with that, for that see http://stackoverflow.com/questions/336859/var-functionname-function-vs-function-functionname – Benjamin Gruenbaum May 27 '14 at 14:12
  • I think this might be referring to increase instead of counter2, so do as @BenjaminGruenbaum says, and simply access it with `count` – ndugger May 27 '14 at 14:13
  • @BenjaminGruenbaum thanks, I understand that in counter2 I can use access this.count if I return count as well (return { count: count, inc : increase , get :getValue }) however, can you help me understand that why this does not have the acess to the count variable if I don't return count? – Xavier May 27 '14 at 14:20
  • Yes, read about dynamic this in JavaScript. – Benjamin Gruenbaum May 27 '14 at 14:21
  • The [`this` keyword](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) does not work like in Java. It denotes the context of how the function was called, instead of holding local variables. – Bergi May 27 '14 at 15:14
  • In your case, `this` refers to the object that you return. Since you never add a property `count` to it, `this.count` simply does not exist. Why would you think otherwise? Everything else would mean some hidden magic is going on, which would be really bad. – Felix Kling May 27 '14 at 15:59

2 Answers2

0

When you call a constructor function with the "new" keyword, the context variable "this" points to itself and is implicitly returned from the end of the constructor function. When you are explicitly returning your new object inc and get functions, you are no longer returning "this" that is created with the constructor anymore. To be able to use with "this", you need to expose inc and get functions on "this" within the constructor function:

function counter2(start) {
    //ensure counter2 function was called with "new" keyword
    if (!(this instanceof counter2)) {
        return new counter2(start);
    }

    this.count = start; 
    this.inc = function(){
         this.count++;
    };

    this.get = function() {
         return this.count;
    };

    //When called with "new" this is implicitly returned, your constructed object.
    //return this;
}

var c2 = new counter2(5);
c2.inc();

As others have pointed out, exposing "count" inside your explicitly returned object would also allow you to access count through "this.count" since count is now a part of the object that you are returning. In this case, "this" will point to the object itself (which will need a count defined).

function counter2(start) {
    var count = start; 

    var increase = function(){
         this.count++;
    };

    var getValue = function() {
         return this.count;
    };

    return {
        count: count,
        inc: increase,
        get: getValue
    }
}

var c2 = new counter2(5);
c2.inc();
Patrick
  • 6,828
  • 3
  • 23
  • 31
0

So to start off I think you should learn a little about the Constructor pattern and 'Inheritance' in javascript.

Constructor Pattern

When you call new counter2(5) the counter2 function attempts to create a new object which would be called this inside the function, so you can add functions to it, which will allow you to access the state of the variables, such as count.

If you are just learning javascript then it would probably be easier for you if you try not to use var inside your counter2 and use the this keyword and have your function looking like the following:

function Counter(start) { this.count = start;

this.increase = function () {
    this.count++;
}

this.get = function () {
    return this.count;
}

}

This is the basics of the Constructor pattern in Javascript.

As I have said this inside the function refers to the object being created, which only happens because you used the new keyword. This can be a complicated subject, but what this is set to inside a function can be changed, which is why im linking Function#bind as some reading.

It can be alot to take in at first, but heres some basic reading to get you started:

Reading

(Constructor Pattern)[http://www.samselikoff.com/blog/2013/11/14/some-Javascript-constructor-patterns/]

(Inheritance and the prototype chain)[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain]

(Function.prototype.bind)[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind]

Good luck!!

iLikePrograms
  • 470
  • 2
  • 9
  • 1
    *"`this` refers to the current scope"*. That is incorrect. Scope and `this` are two completely different things. Also *"`this` is essentially refering to the current scope, so the `increase` function"*: `this` never refers to the function itself unless *explicitly* set to it. – Felix Kling May 27 '14 at 17:43
  • Ofcourse, your right. It had been a long day, I will remove that part as it is incorrect and confusing. I havent answered many questions, hopefully I will get the feel for it and my answers will become alot more clear! Nice profile BTW @FelixKling – iLikePrograms May 28 '14 at 08:55