daemonl

In case you were wondering...

JS106 - This

'this' is a funny little pointer in Javascript. Not so much 'designed' or 'evolved' but... just 'is'. It has some power - so let's delve a little.

console.log(this); // Window  

var a = {   
  f: function()  
  {   
    console.log(this);   
  }   
}  

a.f(); // Object (a)

What we just saw was 'this' meaning two completely different things depending on it's scope.

The idea is that 'this' refers to public members of the object the code is running in, and in the global scope, that means the 'window' of the browser.

Compare the following:

var Constructor = function(){  

    var a = 1;  

    this.add = function(){  
        a += 1;  
    }  
    this.get = function(){  
        return a;  
    }  
}  

var o = new Constructor();  
o.add();  
console.log(o.get());  // 2
var Constructor = function(){  

    this.a = 1;  

    this.add = function(){  
        this.a += 1;  
    }  
}  

var o = new Constructor();  
o.add();  
console.log(o.a);  // 2

They both do the same thing, but the value 'a' in the first one is a private variable, accessible via 'lexical scope' - it is a variable in the same scope of the functions 'add' and 'get', and so 'add' and 'get' have access to it, but nothing outside of the 'Constructor' function has any direct access to it.

In the second example, 'a' is accessible from outside of the constructor function because it is a property of all objects constructed with that function. It is also accessible from the function 'add' from 'this'.

The other main difference between the two: in the first, there is only one 'a' no matter how many objects are created, so a change to one is a change to all, but in the second, there is one 'a' per object which is created, and they are entirely separate from each other.

'this.a' is a Public member

'var a' is a Private Static 'member' (not really a member because it doesn't really belong to the function - but it acts as if it is.)

Public Static isn't really possible in JavaScript, nor is Private non static

When building a constructor function, 'this' refers to the new object which is being created.

When calling a function with dot notation 'o.a', 'this' in 'a' will refer to the second last part of the dots - 'o' in this case. If we had a more complex object set, l.m.n.o.a(), 'this' in 'a' would still be 'o'.

If there is no '.', 'this' will be the window object.

var Constructor = function(){  

    this.a = 1;  

    this.add = function(){  
        this.a += 1;  
    }  
}  

var o = new Constructor();  
o.add();  
console.log(o.a);  // 2  
o['add']();  
console.log(o.a);  // 3

o'add' is exactly the same as o.add(), and 'this' in the function will still be 'o'

Changing 'this'

You know that a function is just an object? Well, you can call a method on any function called 'bind', which you can use to set what 'this' means in the function:

var pre = {  
    a: "I'm pre.a"  
};  
var Constructor = function(){  

    this.a = "I'm o.a";  

    this.get = function(){  
        return (this.a);  
    }.bind(pre);  
}  

var o = new Constructor();  
console.log(o.get()); // "I'm pre.a"

You don't have to permanently redefine 'this' - you can also do it for a single call to the function:

var pre = {  
    a: "I'm pre.a"  
};  
var Constructor = function(){  

    this.a = "I'm o.a";  

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

var o = new Constructor();  
console.log(o.get.call(pre)); // "I'm pre.a"  
console.log(o.get.apply(pre)); // "I'm pre.a"

These two present a little problem - how do you send a parameter to the function? The difference between 'call' and 'apply' is the how that is done:

var pre = {  
    a: "Hello"  
};  
var Constructor = function(){  

    this.get = function(b, c){  
        return (this.a + " " + b + " " + c);  
    }  
}  

var o = new Constructor();  
console.log(o.get.call(pre, "World", "And Others"));  
console.log(o.get.apply(pre, ["World", "And Others"]));

And since the arguments for apply are provided as an array, you can use any array variable in there

var pre = {  
    a: "Hello"  
};  
var Constructor = function(){  

    this.get = function(b, c){  
        return (this.a + " " + b + " " + c);  
    }  
}  

var o = new Constructor();  
var params = ["World", "And Others"];  
console.log(o.get.apply(pre, params));