引子
首先,看这样一个问题,有两个文件fun.js
和main.js
:
// fun.js
let a = 1;
export default function () {
a = a + 1;
console.log(a);
}
// main.js
import fun from './fun.js';
fun();
fun();
fun();
执行结果是什么?
2
3
4
答案很简单。这不就相当于直接把 fun.js
里的函数粘贴到 main.js
里嘛?
let a = 1;
function fun() {
a = a + 1;
console.log(a);
}
fun();
fun();
fun();
然而问题来了,a 存储在哪个作用域?window 上?
全局?
我打印了下:
// main.js
import fun from './fun.js';
fun();
fun();
fun();
console.log(a);
结果 a 的值是undefined
当然 let 修饰的变量是块级作用域,不会放到 window 作用域。于是我修改了下:
// fun.js
var a = 1;
export default function () {
a = a + 1;
console.log(a);
}
然后打印 a,依然是 undefined
。
闭包?
然后有人说是形成了闭包,所以它没有在 window 上,且一直存储在内存中。但是不存在函数嵌套的情况,好像不能构成闭包的条件。
判断一下就好了。但是我怎么来判断是不是闭包呢?
用 webpack 打包成一个文件,再单独 debug 这个文件中的代码。于是,我用 webpack 打包。打包后 debug 如下:
webpack-closure.jpeg果然是闭包。
不对,webpack 相当于把 export/import
手动实现了一遍。export
被它处理成了一个函数。这样就构成了闭包的条件。
我为什么不直接 debug 看看这个变量 a 到底是何方神圣呢?果然还是走了弯路。
ES6 module scope
使用 chrome 直接 debugfun.js
,然后在 scope 里发现了一个东西,module
。
哦,原来如此,我赶紧搜索栏下 module scope
,果然有人跟我有相同的疑问:
https://stackoverflow.com/questions/30287977/es6-module-scope
可以这样理解, js 的作用域分为:
- 全局作用域
- 模块作用域
- 函数作用域
- 块级别作用域
- 闭包作用域(勉强算是把,毕竟 chrome 里都标出来了)
模块作用域的底层是怎样我们不知道,但如果让我们实现一个模块作用域,那自然是通过函数来隔离作用域。
function moduleFun() {
var a = 1;
return function fun() {
a = a + 1;
console.log(a);
};
}
const fun = moduleFun();
fun();
fun();
fun();
也就跟 webpack 思路一样,所以会构成闭包也是理所当然了。
参考文档
https://stackoverflow.com/questions/30287977/es6-module-scope
网友评论