JavaScript示例中具有冲突示例的作用域



var age = 23;
function foo() {
console.log(age);
var age = 65;
console.log(age);
}
foo();

输出:

undefined
65

但是

var a = 'hello!';
first();
function first() {
var b = 'hi!';
second();
function second() {
var c = 'hey!';
console.log(a + b + c);
}
}

输出:

hello!hi!hey!

为什么在第一个函数中age是未定义的,而在第二个函数中,a正确地绑定到hello!

因为当你使用var时,写这个:

function foo() {
console.log(age);
var age = 65;
console.log(age);
}

js认为你写了这个:

function foo() {
var age; // it is undefined
console.log(age);
age = 65;
console.log(age);
}

当您用var声明变量时,局部变量的声明实际上发生在函数的顶部,它会从全局范围中隐藏变量。

同样正如评论中提到的,您应该真正使用letconst,而忘记varvar在这一点上已经过时了

在Javascript中,变量被"吊起",也就是说,即使您将age放在foo的第二行,实际上代码看起来像:

function foo() {
var age; // which in practice means that age = undefined
console.log(age);
age = 65;
console.log(age);
}

这是因为提升-使用var关键字创建变量的众所周知的问题。每次以这种方式声明时,无论在哪里声明,变量都会一直冒泡到函数的开头。这就是的原因

function foo() {
console.log(age);
var age = 65;
console.log(age);
}

类似于

var age = 23;
function foo() {
var age // age hoisted to here
console.log(age);
age = 65;
console.log(age);
}

这也造成了循环和异步操作的问题,如下所示:

function foo() {
for (var i = 0; i <= 6; i++) {
setTimeout(()=>console.log(i), 0)
}
}
foo()

您将得到7中的7,而不是像0,1,2..这样的预期输出,原因是相同的-var声明提升到函数的顶部,它分解了一个循环范围。然后循环结束其工作,i变为7,由于关闭,该值进入setTimeout回调。为了避免这种情况,根本不要使用var,因为ES6constlet都是最佳实践。

最新更新