4

谁能解释为什么以下产生 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

4 回答 4

5

由于 javascripts var 提升,此代码:

(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(即!a === true)

于 2016-11-22T05:41:00.107 回答
1

Jeromanda X 给出了正确的答案,这是由于var 提升,我想补充一下以更好地说明。

您的 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

于 2016-11-22T06:11:36.783 回答
1

避免重新声明,只需像在您的顶级函数中一样进行var a = [1, 2];初始化。a = [1, 2];就像@Jaromanda 解释的那样,该变量是在 JavaScript 中提升的。

于 2016-11-22T05:45:01.827 回答
-2

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

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

这就是我们遇到最有可能“未记录”和“意外”的行为的地方。

op的1at示例

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

让它返回本地值 1,2。我们可以看到bar函数上下文的if条件将宿主函数变量a视为未定义,因此它将!a否定为true

这是为什么?一位评论员坚持要吊装。但是什么吊装?在同一函数的两个版本中,提升原则绝对不会干扰最终结果或行为,唯一的区别在于条件参数:一个检查 'a' 是否为false,另一个检查是否为true

吊装!什么吊装?如果是为了“提升”- !a操作应该明确地返回false,因为 a 已经在更高的上下文上定义了一个真实值,该更高的上下文可以访问主机的任何和每个较低的上下文函数。但恰恰相反

由于 if(!a [false] ) 因此条件返回为true,它允许使用 var 键执行同名变量的新声明好像它遥不可及或不存在在更高的范围内。

它不应该。但它应该。

现在在条件中不否定 if 参数的情况下尝试同样的事情,我们将得到一个错误和一个赋值失败,如下所示:

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

[!same as when using if(!!a) ] 除了现在我们询问 a 是否为真之外,我们什么都没做,这样我们就可以创建一个新的局部 'a' 变量,其值为 [1,2];

到底是怎么回事?!if条件明确需要a参数才能继续进行,它是 查找“向下爬”到函数bar的本地上下文。

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

但是,在控制台日志中,返回了一个局部变量 a 并且它是undefined

这是出乎意料的;矛盾的;挑衅但看似正确!这是正确的,因为本地a变量已初始化,但开始时没有正确获取值。我们试图从更高的上下文中重新声明它,但这是不允许的。

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

于 2016-11-22T05:49:10.377 回答