作用域
ES6 之前 JavaScript 没有块级作用域,只有全局作用域和函数作用域。ES6的到来,为我们提供了‘块级作用域’,可通过新增命令let和const来体现。
作用域链
自由变量
首先认识一下什么叫做 自由变量 。如下代码中,console.log(a)要得到a变量,但是在当前的作用域中没有定义a(可对比一下b)。当前作用域没有定义的变量,这成为 自由变量 。自由变量的值如何得到 —— 向父级作用域寻找(注意:这种说法并不严谨,下文会重点解释)。
var a = 100function fn() {var b = 200console.log(a) // 这里的a在这里就是一个自由变量console.log(b)}fn()
什么是作用域链?
如果父级也没呢?再一层一层向上寻找,直到找到全局作用域还是没找到,就宣布放弃。这种一层一层的关系,就是 作用域链 。
var a = 100function F1() {var b = 200function F2() {var c = 300console.log(a) // 自由变量,顺作用域链向父作用域找console.log(b) // 自由变量,顺作用域链向父作用域找console.log(c) // 本作用域的变量}F2()}F1()
闭包
使用场景:
- 传递参数是函数
function F1 (){var a = 100return function () {console.log(a)}}var f1 = F1 ()function F2 (fn) {var a = 200fn()}F2(f1)
- 返回值是函数
function F1 (){var a = 100return function () {console.log(a)}}var f1 = F1 ()
基于词法作用域书写代码时产生的自然结果,是一种现象
优点:
- 变量长期驻扎在内存中;
- 避免全局变量的污染;
- 私有成员的存在;
缺点
反应迟缓,崩溃, 高延迟其他问题的根因
- 容易造成内存泄漏
垃圾回收语言的内存泄露主要原因就是不需要引用
例子
全局作用域,函数作用域, 块作用域
for(var i = 0; i < 10; i++) {setTimeout(() => {console.log(i)}, 0)}
输出
10个10
想输出0-9
var -> let
输出
0,1,2,3,4,5,6,7,8,9
或者闭包
// 使用闭包for(var i = 0; i < 10; i++) {(function (i) {setTimeout(() => {console.log(i)}, 0);})(i);}
