在下面的示例中,我试图访问函数 outer 中的
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 的调用尝试记录附加到函数 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();
至于下一步要做什么,这真的取决于最终目标是什么。解决这个问题的简单方法是,正如此处评论中所指出的那样,简单地重命名变量。但是,这仍然不能解决尝试通过属性名称而不是变量名称访问变量的主要问题。为了按名称访问变量,只需使用它的名称(如果它们共享范围,则区分名称),而不是尝试访问在这种情况下不存在的属性名称。
因为这里还没有提到它,我将通过利用
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});
您不是在创建对象属性,而是在创建内部变量。您还隐藏了它(也就是说,您在内部范围内定义了另一个同名的对象),这样您就无法访问它们。
基本上你可以访问 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();
但这只会让其他变量变得无用,而且仅仅因为你可以就在函数上设置变量并不是最佳实践。
继续学习。
你可以看看 scope 的概念以获得更清晰,但是第一个 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);
你正在尝试打印 outer.x,而“outer”对象似乎并不存在(我们使用点符号来访问对象成员)。只需将
outer()
中声明的 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()
函数获取您要使用不同名称打印的变量,那么它就不会被该范围内的任何其他变量覆盖。您可以通过向函数声明参数列表来控制函数修改哪些变量,并且只修改那些已经放入带有函数参数的“桶”的变量,而不是那些来自外部范围的变量。我认为一般来说这是一个很好的做法。