Eighteen Blog

说明

在一篇文章里看到这样一个问题。文章地址

文章中会扩展一些其他的内容, 大家可以看过之后再来看我这篇个人的总结

函数声明写在块级作用域中(ES6)

1
2
3
4
5
6
7
8
var a = 0;
if(true){
a = 1;
function a(){}
a = 21;
console.log("里面",a);
}
console.log("外部",a);

请问输出是什么? 答案是:里面21 外面1

小朋友,ni'you
正如我一样,看到答案的我蒙蔽了,然后就继续阅读完全文,感觉还是有点不太明白。最后经过我查询资料我得到了答案。

转换结果

代码转化如下:

1
2
3
4
5
6
7
8
9
10
11
12

var a;
var a = 0;
if (true) {
let a = function a() {
}
a = 1;
window.a = a; //此处为原函数声明的位置
a = 21;
console.log("里面",a);
}
console.log("外部",a);

其实,函数声明放在块级作用域内做了以下几件事。
so, 我想看到了转换后的代码,估计大家就豁然开朗了。

  1. {}内部修改的是let定义的块级a,跟外部没关系。

  2. 所以 a = 1 的时候,外部其实还是为0。

  3. 外部的全局a原本为0, 被window.a = a 同步为了1.

  4. a =21 块级a变成了21,全局a无变化还是1.

那么为啥会这么转换呢????

实质

  1. 函数声明会被提升到块级作用域顶部。

  2. 使用了类似let的方式定义了一个块级作用域的函数同名变量,并赋值。(个人总结)

  3. 函数声明的变量被声明到了全局作用域(或者函数作用域)顶部。

  4. 在函数声明的位置,会将目前块级作用域内的变量的值同步到全局作用域(函数作用域)下。

解释

如下标记 1234 ,我想这样是最直观的。

(window 代表的外层的作用域上下文,意思是if块所在的作用域,因为此处为全局,所以为window)。

1
2
3
4
5
6
7
8
9
10
11
12
13

var a; // 3
var a = 0;
if (true) {
let a = function a() {
// 1,2
}
a = 1;
window.a = a; // 4:此处为原函数声明的位置
a = 21;
console.log("里面",a);
}
console.log("外部",a);

扩展

1
2
3
4

if(true) {
function a( ){}
}

转换为es5为

1
2
3
4
5
"use strict";

if (true) {
var a = function a() {};
}

所以经过我的查找,所有人都不推荐直接在块级作用域内进行函数声明,如果非要,就请使用es5的函数表达式写法。

 评论