如何在JavaScript中访问外部作用域的变量。

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

8
使用三个不同的变量名来代替重复使用三次的x,这样它就可以被访问到。但是如果你使用相同的名称,那么你就只能访问最近的那一个,而无法访问其他的。 - Nicholas Tower
你是想说在上面的例子中,无法在内部函数中访问外部的x吗? - Makedon makedonski
正确。你编写的代码方式使得外部变量在内部函数中无法访问。 - Nicholas Tower
如果你想要一个官方术语,那就是“变量遮蔽”(variable shadowing)。参考链接:https://dev59.com/e2ct5IYBdhLWcg3wqvXL - mhodges
这根本不是变量的工作方式。 - Kevin B
5个回答

2
作用域在JavaScript中不是这样设计的。为了将变量x附加到其作用域,您需要通过名称或此引用引用该作用域的对象。
在您的示例中发生的情况是,您对printX的调用尝试记录附加到函数outer的变量x。在JavaScript中,函数派生自对象,因此它们可能具有附加到它们的属性,因此您没有得到引用错误,而是得到未定义,因为该变量不存在。
有关作用域的更多信息,请参见我的有关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();

关于接下来要做什么,这实际上取决于最终目标是什么。修复这个问题的简单方法是,如评论中所指出的,只需重新命名变量即可。然而,这仍然不能解决试图通过属性名而不是变量名访问变量的主要问题。为了通过名称访问变量,只需使用它的名称(并区分共享作用域的名称),而不是尝试访问在此情况下不存在的属性名。

2

既然这里还没有提到,我将通过利用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});


0

你没有创建一个对象属性,而是内部变量。你还遮蔽了它们(也就是在内部作用域中定义了另一个同名变量),所以你无法访问它们。

基本上,你可以访问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();

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

继续学习吧。


0
你可以查看作用域的概念以获得更清晰的理解,但第一个x在全局作用域中,可以在函数内部访问,但是你重新分配了变量值为20在外部函数中。如果你在外部函数中console log 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);

}

outer(); console.log(x);


0

你试图打印outer.x,但是'outer'对象似乎不存在(我们使用点符号来访问对象成员)。只需将在outer()中声明的x的值传递给inner(x)函数以将其打印到控制台:

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

只要inner()函数使用不同的名称获取您想打印的变量,它就不会被该范围内的任何其他变量所遮蔽。您可以通过声明参数列表来控制函数修改或使用的变量,并仅使用那些已经放入该“桶”中的变量作为函数的参数,而不是外部作用域中的变量。我认为这通常是一个好习惯要遵循的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接