简体   繁体   中英

How to access a variable from outer scope in JavaScript

In the example bellow, I am trying to access the x that is in the function outer.

I was expecting to get 20 as an output, however the output is undefined .

Can someone explain why is that happening, and is there a way to access the outer x?

var x = 10;
function outer() {
    var x = 20;
    function inner() {
        var x = 30;
        function printX() {
            console.log(outer.x);
        }
        printX();
    }
    inner();
}
outer();

Scopes aren't designed like that in JavaScript. In order to attach the variable x to its scope, you would need to reference the object for that scope either by name or by this reference.

What is happening in your example is that your call to printX attempts to log the variable x attached to the function outer. functions derive from objects in JavaScript, and as a result they may have properties attached to them, so instead of giving you a reference error, you get undefined instead, as the variable does not exist.

For more information on scoping, please see my answer on scope in JavaScript .

var x = 10; // Globally scoped variable named "x"
function outer() {
    var x = 20; // Locally scoped to outer function variable named "x"
                // in outer function, this variable takes precedence over the
                // globally scoped x which was 10
    function inner() {
        var x = 30; // Locally scoped to inner function variable named "x"
                    // in inner function, this variable takes precedence over the
                    // parent scoped x which was 20
        function printX() {
            console.log(outer.x); // Tries to read "x" property of the outer function
                                  // If this had been console.log(x) it would give 30 because it is scoped to the function inner's variable environment
        }
        printX();
    }
    inner();
}
outer();

As for what to do going forward, it really depends on what the end goal was. The simple way to fix this would be, as pointed out in comments here, to simply rename the variables. However, that still wouldn't fix the main issue of trying to access the variable by property name instead of by variable name. In order to access a variable by name, simply use its name (and differentiate the names if they share scope), as opposed to trying to access the property name which in this case doesn't exist.

Since it hasn't been mentioned here yet, I will add another possible way to do this by leveraging this and scope by calling the functions with .apply() , like so:

 var x = 10; function outer() { var x = 20; function inner() { var x = 30; function printX() { // this now contains all 3 x variables without adding any parameters to any of the functions console.log("Window x:", this.windowX); console.log("Outer x:", this.outerX); console.log("Inner x:", this.innerX); } // pass through existing context (which we got from inner.apply(...) down below, as well as add // inner() x value to the new context we pass to printX() printX.apply({...this, innerX: x}); } // pass through existing context (which we got from outer.apply(...) down below, as well as add // outer() x value to the new context we pass to inner() inner.apply({...this, outerX: x}); } // pass through window level x as "this" to outer(). Technically it's still available via window.x, // but this will be consistent with the others outer.apply({windowX: x});

You are not creating an object attribute but internal variables. Which you also shadow (that is that you define another with the same name in an inner scope) so that you cannot reach them.

Basically you can access outer.x but you have not set it (only a function scoped variable named x). And to answer your question "if you can get to that variable": No sorry. since you have shadowed it by defining an inner variable with the same name.

What you could do is this:

var x = 10;
function outer() {
    outer.x = 20;
    function inner() {
        inner.x = 30;
        function printX() {
            console.log(outer.x);
        }
        printX();
    }
    inner();
}
outer();

but that would just make the other variables useless, and also setting variables on functions just because you can is not the best practice.

Keep learning.

You can take a look at the concept of scope to get more clarity, but the first x is in the global scope and can be accessed within the function, but you reassigned the variable value to be 20 within the outer function. If you console log the value of x within the outer function, but not inside the inner function, the result will be 20. You assigned the value 30 to x in the inner function, so when you access x within the inner function, it will be 30. If you console.log(x) in each location, you will see the different results.

var x = 10;

function outer() {
    var x = 20;

function inner() {
    var x = 30;

    function printX() {
        console.log(x);
    }

    printX();
}

inner();
console.log(x);

}

outer(); console.log(x);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM