Javascript 这些块的JS范围是如何工作的?
有人能解释为什么下面的结果是1,2,而另一个结果是5吗?他们不应该都生产5个吗Javascript 这些块的JS范围是如何工作的?,javascript,scope,closures,lexical-closures,Javascript,Scope,Closures,Lexical Closures,有人能解释为什么下面的结果是1,2,而另一个结果是5吗?他们不应该都生产5个吗 //produces 1,2 (function () { var a = [5]; function bar() { if (!a) { var a = [1, 2]; } console.log(a.join()); } bar(); })(); 基于阅读了一些关于JS闭包的文章,我希望他们都能产生5。似
//produces 1,2
(function () {
var a = [5];
function bar() {
if (!a) {
var a = [1, 2];
}
console.log(a.join());
}
bar();
})();
基于阅读了一些关于JS闭包的文章,我希望他们都能产生5。似乎在任何地方都找不到一篇文章来解释为什么第一个块会产生相反的结果
//produces 5
(function () {
var a = [5];
function bar() {
if (a) {
console.log(a.join());
}
else {
console.log([1, 2].join())
}
}
bar();
})();
谢谢 由于Java脚本,此代码:
(function () {
var a = [5];
function bar() {
if (!a) {
var a = [1, 2];
}
console.log(a.join());
}
bar();
})();
等同于此代码:
(function () {
var a = [5];
function bar() {
var a; // a === undefined at this point
if (!a) {
a = [1, 2];
}
console.log(a.join());
}
bar();
})();
因此,您可以看到,
a
在测试if条件时确实是false
(即!a==true)避免重新声明var a=[1,2]代码>并初始化为a=[1,2]代码>在顶部函数中。就像@Jaromanda解释的那样,变量是用JavaScript提升的。我们知道每个函数都创建自己的上下文,并且可以有自己的局部变量和东西
因此,我们假设,在最顶层函数上下文中编写var a=[5]
,将使它在我们可能编写的任何新嵌套函数的上下文中可用和可访问
这就是我们遇到一种行为的地方,这种行为很可能是“未记录的”,也可能是“意外的”
op的1at示例
function bar(){
if(!a) {
var a = [1,2];
}
console.log(a);
}
>> 1,2
使其返回1,2的局部值。
在这里我们可以看到,条函数上下文的if条件将宿主函数变量a视为未定义,因此它将其否定!a到真
为什么呢?
一位评论员坚持认为这是错误的。但是什么呢?
在同一函数的两个版本中,提升原理绝对不会干扰最终结果或行为,唯一的区别在于条件参数:一个检查“a”是否为假,另一个检查“a”是否为真
吊运!什么吊装?
如果是为了“提升”——!一个操作应该无误地返回false,因为在主机的任何和每个较低上下文函数都可以访问的较高上下文中,已使用truthy值定义了一个。但恰恰相反
如果条件返回中的if(!a[false])因此为true,则它允许使用var键执行一个同名的变量的新声明,就好像它无法到达或根本不存在于更高的范围中一样
它不应该这样。但它应该这样做
现在,在不否定条件中的if参数的情况下尝试相同的操作,我们将得到一个错误和一个赋值失败,如中所示:
function bar(){
if(a) {
var a = [1,2];
}
console.log(a);
}
>> undefined
[!与使用if(!!a)时相同]
我们没有做任何更改,只是现在我们询问a是否为真,以便我们可以创建一个新的局部“a”变量,其值为[1,2]
发生什么事了强>
如果有条件,明确需要a参数为true才能继续,则向上查找并“向下爬升”到函数栏的本地上下文
出于某种原因,它被视为试图重新声明宿主函数的变量,并拒绝初始化本地上下文中具有相同名称的新变量并将其赋值。这是一个混淆,因为条件现在引用了它拒绝声明的宿主变量,并将值赋给局部a
但是,在控制台日志上,返回了一个局部变量a,该变量未定义
这是出乎意料的;矛盾的挑衅但似乎正确!
这是正确的,因为局部a变量已初始化,但没有正确获取开始时的值。我们试图从更高的上下文中重新声明一个,但这是不允许的
唯一的好处是——不同浏览器之间的行为似乎是一致的。Jeromanda X给出了正确的答案,这是因为,我只想添加一些更好的说明
您的两个代码块的不同之处在于,您在其中一个代码块中创建了新变量,而在另一个代码块中没有创建新变量。为了公平起见,您应该将代码块#2更改为以下内容
//produces [1,2] now
(function () {
var a = [5];
function bar() {
if (a) {
console.log(a.join());
}
else {
var a = [1,2];
console.log(a.join())
}
}
bar();
})();
如果您在两个代码块中都省略了var
,您就不会遇到此范围界定问题,这两个代码块都会产生5
,您可以通过在函数顶部声明变量来避免此类问题,并且不再担心提升,正如最佳实践所规定的那样。@torazaburo我听说过,但你能提供一个来源吗?@jkris你可以从这里开始:@torazaburo Crockford,很好!谢谢允许执行以下声明否,声明不按顺序执行;正如其他答案所表明的那样,它们被挂起。是的,如果变量“a”被定义,则if条件测试例如,true,并且由于变量a已经为true,因此条件允许局部var a=[1,2]代码>待执行。我不认为我们在这里讨论的是同一个问题。我认为我必须重写我的答案,因为op询问了其他问题,但编写了两段逻辑不一致的代码。@JaromandaX-我刚刚在FF控制台中测试了第一个examaple,遇到了一个错误-这完全出乎意料-测试这个:(函数(){var a=[5];函数条(){if(a){var a=[1,2];}控制台.log(a.join();}条();})()代码>你怎么看?谢谢你指出了正确的方向。我读了一些其他的文件,现在有了这个想法。只要理解下面的陈述,困惑就会消失。“提升是将变量和函数声明移动到函数范围顶部的机制。”提升与问题完全无关。您对@Bekimbacj造成了什么损害?谢谢。是的,我知道这应该避免。我只是不知道这就是为什么和术语的原因