这些块的JS范围如何工作?

时间:2016-11-22 05:35:37

标签: 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 5
(function () {

    var a = [5];

    function bar() {
        if (a) {
          console.log(a.join());
        }
        else {
          console.log([1, 2].join())
        }
    }

    bar();

})();

谢谢!

4 个答案:

答案 0 :(得分:5)

由于javascripts var hoisting,此代码:

(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();
})();

所以你可以看到,当测试if条件时,a确实是falsey(即!= === true)

答案 1 :(得分:1)

避免重新声明var a = [1, 2];,只在初始函数中初始化为a = [1, 2];。就像@Jaromanda解释的那样,变量在JavaScript中被提升。

答案 2 :(得分:1)

Jeromanda X给出了正确的答案,这是由于var hoisting,我只是想补充说明更好。

您的2个代码块的不同之处在于您在一个中创建了一个新变量而在另一个中没有创建新变量。为了公平起见,您应该将代码块#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

答案 3 :(得分:-2)

我们知道每个函数都创建自己的上下文,并且可以拥有自己的局部变量和事物。

因此,我们假设在最顶层函数上下文的上下文中编写var a = [5]将使它可用并可由我们编写的任何新嵌套函数的上下文访问。

这就是我们遇到一种很可能没有记录的行为的地方。以及'意外'。

op

的第1个例子
function bar(){
    if(!a) { 
           var a = [1,2];
          }
    console.log(a);
    }
>> 1,2

返回本地值1,2。 我们可以看到 bar 函数的 if 条件 context 正在将主机功能变量 a 视为 undefined < / em> 因此它将 !a 否定为 true

为什么? 评论员坚持要求提升。但什么悬挂? 在相同函数的两个版本中,最终结果或行为绝对不会干扰提升原则,其中唯一的区别在于条件参数:一个检查是否&#39; a&#39;是 false ,另一个是

起重!吊什么? 如果它是为了'#34;吊装&#34; - !a 操作应无误地返回 false ,因为a已经使用 truthy 值定义在更高的上下文中,可以访问主机的任何和每个较低的上下文功能。但恰恰相反

由于if(!a [false])因此 true 来自条件返回,它允许执行 a <的新声明/ strong> 变量使用var键使用相同的名称,就像它不可及或根本不存在于更高的范围内一样。

它不应该。但它应该。

现在尝试相同的事情而没有否定条件中的if参数,我们会得到错误和赋值失败,如:

 function bar(){
    if(a) { 
           var a = [1,2];
          }
    console.log(a);
    }
>> undefined

[!与使用if(!! a)时相同] 我们之后什么也没有改变,只是现在我们问的是否是真的,这样我们就可以创建一个新的本地&#39; a&#39;变量值[1,2];

发生了什么事? if 条件明确需要 参数 true 才能继续查找并且&#34;将其降下来&#34;到功能 的本地环境。

由于某种原因,它被处理为尝试重新声明主机函数的变量并拒绝初始化并为本地上下文中具有相同名称的新变量赋值。这是一个混乱,因为条件现在引用主机变量,它拒绝声明并为本地a赋值。

但是,在控制台日志中,正在返回一个局部变量a,它是 未定义

这是出乎意料的;矛盾的;挑衅但看似正确! 这是正确的,因为本地 a 变量已初始化但未正确获取值。我们试图从更高的背景重新声明一个,但这是不允许的。

唯一的好处是 - 浏览器中的行为似乎是统一的。