Karl
Karl

Reputation: 1864

Javascript closures, 'this' keyword and variable namespaces

I'm trying to understand how the this keyword works.

This article The this keyword states

"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."

function someClosure() {
    var myVal0, myVal1, myVal2;

    init = function (myVal0, myVal1, myVal2) {

        myVal0 = myVal0;
        this.myVal1 = myVal1;
        this.myVal2 = myVal2;

    };

    getMyVal0 = function() { return myVal0 };
    getMyVal1 = function() { return myVal1 }
    getMyVal2 = function() { return this.myVal2 }
};

I surmise that getMyVal0 is undefined after init() is called because of a naming clash (the assignment is ambiguous).

But (after calling init()) why does getMyVal1 return undefined? The reference to myVal1 should not be ambiguous. Does Javascript require an explicit use of this? getMyVal2 returns the expected value, but again, I'm surprised that I need the explicit this.

Please clarify this behavior.

Ultimately, I'm trying to establish a naming convention for function arguments when initializing member variables. By industry convention, IRR is IRR and it seems this should allow me to avoid comming up with two names for a variable (without always referencing the member variable with this.) What's the convention for doing what I want to do?

Upvotes: 2

Views: 1373

Answers (3)

Bergi
Bergi

Reputation: 665145

Read this introduction to the this keyword at MDN.

The value of this depends on how you call the function. But you don't call the init at all, and all variables are still undefined.

By industry convention, this should allow me to avoid comming up with two names for a variable

No. this in JavaScript is different from this in other languages like Java. It will not let you access variables from a higher scope. In your case, the arguments of the init function just shadow the variables from myClosure - you can't access them. You need to rename them if you want them. Use this script:

var init, getMyVal; // global, or at least "outer", variables

function closure() {
    var myVal, myVal2; // scoped to the closure

    // all the following function can access them
    init = function(val, myVal2) {
        myVal = val; // assign the argument to the closure variable
        // myVal2 === myVal2 - sorry, this only refers to the argument
    };
    getMyVal = function() {
        return myVal; // get the closure variable
    };
};
closure(); // execute it - you might also have used a immediately-executing function

init("some value");

getMyVal(); // "some value"

Btw, you might combine the closure and init call to only one function:

var getMyVal;
function initClosure(myVal) {
    // the argument is scoped to this function, like a var declaration

    getMyVal = function() { return myVal; };
}
initClosure("some value");

getMyVal(); // "some value"

Upvotes: 2

jAndy
jAndy

Reputation: 236122

The var keyword in ECMAscript 2-6-2 3rd edition aswell as in ES5 pretty much only says, "declare that variable in the current context". this on the other side always refers to the "object of invocation" (how I like to call it), which is a different story.

The context for a function is not directly accessible through Javascript itself, its only existent in the underlaying lexicalEnvironment (ES5) or the Execution Context -> Activation Object (ES3).

So, by explicitly calling this.xxx you are reading and writting to the OOI (which can change, based on how the method was called). The "Activation Object" holds

  • formal parameters
  • variables declared by var
  • function declarations

All of those things are not stored in the object which is referred by this.

Upvotes: 3

Pointy
Pointy

Reputation: 413916

Well PPK is simply incorrect in that article. The this pointer has a value that is determined anew with each function call. There is no such thing as "method ownership" in JavaScript. The this pointer gets a value when a method is invoked as a result of an object property reference, that's true, but the same method can be a property of many different objects.

Aside from that, it's important to understand that local variables in a constructor function are completely distinct from object properties of an object this refers to. That is,

function Constructor() {
  var x, y;

  x = "whatever";
}

In that code, the variables "x" and "y" are local variables, and not properties of an object.

Upvotes: 3

Related Questions