繁体   English   中英

如何从 JavaScript 的外部作用域访问变量

[英]How to access a variable from outer scope in JavaScript

在下面的示例中,我试图访问函数外层中的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();

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

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

有关作用域的更多信息,请参阅我对 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();

至于接下来要做什么,这实际上取决于最终目标是什么。 解决这个问题的简单方法是,正如这里的评论中所指出的,简单地重命名变量。 但是,这仍然无法解决尝试通过属性名称而不是通过变量名称访问变量的主要问题。 为了按名称访问变量,只需使用其名称(并区分名称,如果它们共享范围),而不是尝试访问在这种情况下不存在的属性名称。

由于这里还没有提到它,我将添加另一种可能的方法,通过使用.apply()调用函数来利用this和作用域,如下所示:

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

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

基本上你可以访问outer.x,但你没有设置它(只有一个名为x的函数范围变量)。 并回答你的问题“如果你能得到那个变量”:不抱歉。 因为你通过定义一个同名的内部变量来隐藏它。

你可以做的是:

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

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

保持学习。

您可以查看范围的概念以获得更清晰的信息,但是第一个 x 在全局范围内并且可以在函数内访问,但是您在外部函数内将变量值重新分配为 20。 如果在外部函数中控制台记录 x 的值,而不是在内部函数内部,则结果将为 20。您在内部函数中将值 30 分配给 x,因此当您在内部函数中访问 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);

}

外(); 控制台日志(x);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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