如何从JavaScript的外部范围访问变量

时间:2018-09-06 21:56:57

标签: javascript scope

在下面的示例中,我试图访问外部函数中的x

我原本希望得到20作为输出,但是输出为undefined

有人可以解释为什么会这样吗,并且有办法访问外部x吗?

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

4 个答案:

答案 0 :(得分:1)

作用域不是在JavaScript中那样设计的。为了将变量x附加到其作用域,您需要通过名称或此引用来引用该作用域的对象。

在您的示例中发生的是,您对printX的调用尝试记录附加到外部函数的变量x。函数是从JavaScript中的对象派生的,因此它们可能具有附加的属性,因此,由于变量不存在,因此没有给您提供引用错误,而是得到了undefined。

有关范围界定的更多信息,请参阅我的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();

关于下一步该做什么,实际上取决于最终目标是什么。如此处的注释所指出的,解决此问题的简单方法是简单地重命名变量。但是,这仍然不能解决试图通过属性名而不是变量名访问变量的主要问题。为了按名称访问变量,只需使用其名称(如果它们共享作用域,则区分名称),而不是尝试访问在这种情况下不存在的属性名称。

答案 1 :(得分:0)

您不是在创建对象属性,而是在创建内部变量。您还会隐藏哪一个(也就是说,您在内部作用域中定义了另一个具有相同名称的对象),以便无法访问它们。

基本上,您可以访问external.x,但尚未设置它(仅是一个名为x的函数作用域变量)。并回答您的问题“如果可以使用该变量”:对不起。因为您已经通过定义一个具有相同名称的内部变量对其进行了遮盖。

这是您可以做的:

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

但这只会使其他变量变得无用,并且仅仅因为您可以而在函数上设置变量并不是最佳实践。

继续学习。

答案 2 :(得分:0)

由于尚未在此处提及,因此我将添加另一种可能的方法来利用this和范围,通过使用.apply()调用函数来实现此目的,就像这样:

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});

答案 3 :(得分:0)

您可以看一下范围的概念来获得更多的清晰度,但是第一个x在全局范围内,可以在函数中访问,但是您将变量值重新分配为20个内部函数。如果您在外部函数中而不是内部函数中记录x的值,则结果将为20。您在内部函数中为x分配了值30,因此当您在内部函数中访问x时,它将是30。如果在每个位置都使用console.log(x),则会看到不同的结果。

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);