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