LebGeeks

A community for technology geeks in Lebanon.

You are not logged in.

#1 December 14 2013

rolf
Member

JavaScript context and "this"

I'm just starting to deepen my knowledge on that topic. I'm was just reading this article (and I'm not understanding all of it):

http://alistapart.com/article/getoutbindingsituations

(referred from this page:)

http://stackoverflow.com/questions/9620 … -self-this

So I'm less ignorant than before, but still not as enlightened as I'd like to.

I've run into some "this" issues before, and I usually solve them by explicitly copying the value of this to a variable - it also avoids ambiguities... example:

function myClass() {
     var myClassContext = this;
     this.someProperty = "nice";
     this.myMethod = function(arg) {
         // some code
         someElem.onclick = function(el) {
              el.setAttribute('class', myClassContext.someProperty);
         }
     }
}

So, here I assigned the value of this to myClassProperty, and I can further use it without running into ambiguous situations or errors.
Another thing that can help is strict mode.

That's usually the type trouble I may run into and how I solve it. I guess I don't do a lot of passing around function pointers.

But I'd like to understand how it all works, and have more insight on the topic, and as I research it, I'm wondering if there are any JavaScript expert here who have a say on the topic...

So, does a JavaScript function simply inherit the context within which it's called? Or is there more to it?

Last edited by rolf (December 15 2013)

Offline

#2 December 15 2013

rolf
Member

Re: JavaScript context and "this"

Regarding the value of "this" in JavaScript, I have to mention this as a comprehensive yet clear answer:
http://stackoverflow.com/questions/3127 … 40#3127440

So that's one concern less.

I wonder why nobody has answered. Maybe the forums are not that active on weekends. People are waiting to be at their office to log in here!

Offline

#3 December 15 2013

Joe
Member

Re: JavaScript context and "this"

Here's the minimum you need to know, to understand how this is evaluated. Every function in your program has access to this and its value depends on the function's invocation. There are 4 different cases:

  • Method invocation

  • Function invocation

  • Construction invocation

  • Apply invocation

Method invocation

You are probably aware that a method is just a function that is a property of an object. When evaluated inside a method, this has the value of the object holding that method. Quick example:

var foo = {
    value: 0,
    increment: function () {
	this.value += 1;
    }
}

foo.increment();
console.log(foo.value); // 1

foo.increment();
console.log(foo.value); // 2

this binding to the calling object is done at invocation time, which allows reuse of functions. For instance:

function foo() {
    this.value += 1;
}

var a = {
    value: 0,
    inc: foo
}

var b = {
    value: 10,
    inc: foo
}

a.inc();
a.inc();
b.inc();

console.log(a.value); // 2
console.log(b.value); // 11
Function invocation

When a function is not invoked as a method, this is bound to the global object window (or document).
For instance:

var a = 2;

function foo() { console.log(this.a);}
foo(); // 2

Beware that this isn't bound to the scope of the outer function. What does that mean? Take a look at this code:

var value = 100;

var myObject = {
    value: 0,
    myMethod: function () {

	function foo() {
	    this.value += 1;
	    console.log(this.value);
	}

	foo();
    }
}

myObject.myMethod(); // 101

Why does this code output 101 and not 1? Because the moment foo() is invoked, it's not invoked as a method but as a function, so this is bound to the global object and not myObject. To avoid this problem, here's a very common idiom in JavaScript:

var value = 100;

var myObject = {
    value: 0,
    myMethod: function () {

        var self = this;

	function foo() {
            self.value += 1;
	    console.log(self.value);
	}

	foo();
    }
}

myObject.myMethod(); // 1

self is not a special variable, so it's not treated any differently than others. Unlike this, it's perfectly okay to define self in the outer scope and the function foo will have no problem fetching self outside.

(I hope this gives a specific answer to your question)

Constructor invocation

A constructor is a function called after the new prefix. These functions create new objects, and this is bound to the object being created.

function foo () {
    this.value = 0;
}

var a = new foo();

console.log(a.value); // 0
Apply invocation

apply() is a function that is familiar to the programmers working in a Functional Programming style. It's a function that allows to construct a list of arguments dynamically and apply another function to them.

You can find something similar in most modern dynamic languages. In JavaScript, apply() is a method to all the other functions. Remember that in JS, everything is an object, even a function, and every object can have methods. It takes 2 arguments:

  • The value of this

  • An array of parameters

As you can see, in this type of invocation, the binding of this is very explicit and you won't have to worry about it. Here's how you can use it:

function sum(a, b) {
    return a + b;
}

console.log(sum.apply(null, [4, 6])); // 10

And here's how you can take advantage of this:

var myObject = {
    value: 10,
}

function foo () {
    return this.value + 1;
}

console.log(foo.apply(myObject, [])); // 11

Usually, you won'd be dealing with the apply invocation pattern very often.

More info

For a more detailed explanation of this, as well as solid (and opinionated) insight into JavaScript, I strongly recommend JavaScript the Good Parts by Douglas Crockford.

Offline

#4 December 17 2013

rolf
Member

Re: JavaScript context and "this"

Thanks a lot, Rahmu, for the explanation.
This may very well be the clearest explanation I've had on the topic.
Thanks for pointing out the odd case about this not being bound to the outer function - I've missed that one.

I've tried the same example code you gave but inside an instantiated object(see code below), and with the same results!

So although "this" is bound to the instantiated object (what you call "constructor invocation"), if "this" is found in any functions within the constructor function, it will point back to the global scope! I've had some difficulty believe it, and to be honest it doesn't make much sense to me and is pretty counter-intuitive, but hey, web standards... This may seem confusing because JavaScript functions normally inherit their outer variables, but hey, "this" is not a variable, but a keyword, after all. Well, you explained it best.

I also tried out some of your examples in strict mode, and, instead of reading from the global object, it just throws an error, which sounds like a sane thing to do - one more reason to use strict mode, for me. It appears that, in strict mode, "this" does not exist within the "function invocation" case.

var value = "global var";

function myObject() {
    this.value = "class var";
    console.log("In constructor: " + this.value);
    this.myMethod = function () {
        console.log("in myMethod(): " + this.value);	
    	function foo() {
            console.log("in myMethod() -> foo(): " + this.value);
    	}
    	foo();
    }
    function foo2(){
       console.log("in foo2(): " + this.value);
    }
    foo2();
}
console.log("calling constructor");
var myObj2 = new myObject();
console.log("calling method myMethod()")
myObj2.myMethod();

// calling constructor
// In constructor: class var
// in foo2(): global var
// calling method myMethod()
// in myMethod(): class var
// in myMethod() -> foo(): global var

Last edited by rolf (December 17 2013)

Offline

Board footer