bizi
bizi

Reputation: 3457

Javascript: got 'undefined' when using 'this' to access outer scope variable in 'private' child function

I have a habit of setting all my variables to its parent scope, instead of calling them implicitly:

function outer() {
    var x, y;
    function inner() {
        var x = this.x;
        x = ...// doing stuff here
        y = ....// implicit calling parent variable
    }
}

so that if I mistype my variable, it won't go to global space. But it seems like declare variable with this within private function will return me undefined:

function f() {
    var x = [0];
    function f1() { 
        console.log('f1:', this.x, x); 
        f2(); 
    }
    function f2() { 
        console.log('f2:', this.x, x); 
    }
    return { x:x , f1:f1 };
}

var foo = f();    
foo.f1();
    //output
    f1: [0] [0]
    f2: undefined [0]

If I understand it correctly, it shouldn't happen, as both f1 and f2 should have access to its outer scope by using this. Is there any concept I am missing here? Or is it something I just have to live with for now?

Update: To clarify, my main concern is why there is the difference between f1 and f2. I prefer to keep f2 hidden because it will do some internal works, and other developers should not use it when they declare something from f().

Upvotes: 3

Views: 2364

Answers (3)

Zoltan.Tamasi
Zoltan.Tamasi

Reputation: 1391

Also try this:

function f() {
    var x = [0];
    function f1() { 
        console.log('f1:', this.x, x); 
        f2.call(this); 
    }
    function f2() { 
        console.log('f2:', this.x, x); 
    }
    return { x:x , f1:f1 };
}

var foo = f();    
foo.f1();

This way the context of f2 will be properly set.

In your code this in f2 refers to the window object, because f2 wasn't declared as a method. f1 was declared as a method of the returned object when writing { x:x , f1:f1 }. In f2 x is visible not because it is run in the scope of f() but because f2 gets it as a closure. That means in f2, all variables will be visible that was in the same scope when it was created.

What the this refers to will be set at invocation time. If you run a function as property of an object like foo.f1() it is considered as a method, and this will be set to the object. But when you just invoke a function like f2() the scope will be the same it was invoked in, in your case it is the window object, because foo is a global in the window object.

In f1 this refers to the hidden f(), therefore if you want f2 also be run in that scope you can use f2.call(this). The argument of .call() will be the this of the function when run.

Upvotes: 4

David G
David G

Reputation: 96810

You returned this from the function:

{ x : x, f1 : f1 }

This sets the the this objects properties to the above. f2 is not apart of the object so it can't access the this that it refers to.

Upvotes: 0

Vlad
Vlad

Reputation: 2565

When your f function returns an object, it doesn't have f2 method. f2 method is an inner method of f and exists only in its scope.

If you use this code:

function f() {
    var x = [0];
    function f1() { 

        console.log('f1:', this.x, x); 
        this.f2(); 
    }
    function f2() { 
        console.log('f2:', this.x, x); 
    }
    return { x:x , f1:f1, f2:f2};
}

var foo = f();    
foo.f1();

then this in f1 method will have access to the f2 method of this, and object's f2 method will return the correct x.

Upvotes: 0

Related Questions