js函数声明与window属性问题,解释一下结果

控制台运行结果:
微信图片_20200622100018.jpg

运行代码如下:

var a=0;
if(true){
    console.log(window.a,a);
    a=1;
    console.log(window.a,a);
    function a (){};
    console.log(window.a,a);
    a=21;
    console.log(window.a,a);
}
console.log(window.a,a);

麻烦大神解释一下,第三次打印结果为什么是1,1呢?

阅读 3.1k
4 个回答

首先要记住:函数声明置顶比变量声明置顶更优先

因为在预解析阶段变量只声明了,但未赋值,而函数不一样,它在预解析阶段就已经声明和赋值了,它的值就是函数这个对象

然后来看代码:
1、var a = 0:声明了一个变量a,并赋值为0
2、看if里面代码;我们先就看a=1function a(){}

// 因为存在变量提升,代码可以分析为这样,先不看console
function a(){}
a = 1

开始执行if代码块,if代码块内有一个函数名为a的函数声明,
且函数a下面有一个变量名为a的变量,且赋值为1,这里便开始了难点分析。

首先看函数a,由于在执行if代码块的时候,并没有调用函数a,因此函数a并没有起作用;
但是执行到a=1的时候,js是这样做的:

1.首先查找变量a的地址,从系统内存中开始按照作用域链查找;
2.由于作用域链的查找顺序是由里向外的,故要先从if代码块里面开始查找;
3.在查找的过程中,发现if代码块中已经声明了一个函数名为a的函数(重名问题!),
所以查找到函数名为a的函数后,这里便不再往外查找;

所以这里的a=1其实是将1赋值给了函数名为a的这个函数对象!

3、第一个consolewindow.a找的是全局的变量a,在全局下已经声明有了a,所以值为0,后面的a会现在if代码块里查找,变量提升了,所以打印的是function a(){}
4、执行到a=1;因为没有var关键字,所以a相当于一个全局变量,此时a就会覆盖原来a的值,变为1;而if代码块里也直接找寻到名为a的函数,所以将a赋值为1,因此第二个console值为 0, 1
5、第三个console,此时已经赋过一次值,在打印,就是1, 1
6、第四个consolea=21,在if代码块里查找,找到了函数名a,将值赋给了这个函数对象;所以这次打印的是1,21
7、第五个console,就是打印全局的a,所以是1, 1

以上就是我的理解,如果有错,欢迎指出,共同理解进步哈?

// 先进行变量提升
var a=0; // global 变量 a = 0 
if(true){
    // 变量提升
    function a (){}; // block 变量 a 是函数
    console.log(window.a,a);  // 0, function(){}
    a=1; // block 变量 a = 1;
    console.log(window.a,a);  // 0, 1 
    // 当局部变量有两个同名对象时,先执行的对象会将自身的具备特性赋给后面的变量,
    // 此时函数声明是 global 变量,所以会把 1 赋值给 window.a
    function a (){}; 
    console.log(window.a,a); // 1, 1
    a=21; // block 变量 a = 21
    console.log(window.a,a); // 1, 21
}
console.log(window.a,a); // 1, 1

这题见过不下五次,每次也没特别好的解释,现在的答案也是我通过打断点,和查阅一些文章得出的结论,仅供参考,欢迎讨论。

附上参考链接:
https://my.oschina.net/zzjweb...
https://segmentfault.com/a/11...

看到过的类似的内容:
https://stackoverflow.com/que...
https://stackoverflow.com/que...

所以应该可以理解为:

var a0 = undefined;
// if 语句块内的函数声明的标识符 a 和外面的 var a 是同名的。为了后续表达方便,加个后缀

a0 = 0;
if (true) {
    var a1 = function a() {};
    console.log(window.a, a);
    // 即 console.log(a0, a1),下同
    // 所以打印 0  ƒ a (){}
    a1 = 1;
    console.log(window.a, a);
    // 0  1
    function a (){};
    // 这里应该理解为赋值 a0 = a1
    console.log(window.a, a);
    // 1  1
    a1 = 21;
    console.log(window.a, a);
    // 1  21
}

console.log(window.a, a);
// 即 console.log(a0, a0);
// 1  1

规范:
http://www.ecma-international...
另外 Safari 上的表现并不是这样的。

image.png这个也奇怪

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏