作用域
ES6 之前 JavaScript 没有块级作用域,只有全局作用域和函数作用域。ES6的到来,为我们提供了‘块级作用域’,可通过新增命令let和const来体现。
作用域链
自由变量
首先认识一下什么叫做 自由变量 。如下代码中,console.log(a)
要得到a变量,但是在当前的作用域中没有定义a(可对比一下b)。当前作用域没有定义的变量,这成为 自由变量 。自由变量的值如何得到 —— 向父级作用域寻找(注意:这种说法并不严谨,下文会重点解释)。
var a = 100
function fn() {
var b = 200
console.log(a) // 这里的a在这里就是一个自由变量
console.log(b)
}
fn()
什么是作用域链?
如果父级也没呢?再一层一层向上寻找,直到找到全局作用域还是没找到,就宣布放弃。这种一层一层的关系,就是 作用域链 。
var a = 100
function F1() {
var b = 200
function F2() {
var c = 300
console.log(a) // 自由变量,顺作用域链向父作用域找
console.log(b) // 自由变量,顺作用域链向父作用域找
console.log(c) // 本作用域的变量
}
F2()
}
F1()
闭包
使用场景:
- 传递参数是函数
function F1 (){
var a = 100
return function () {
console.log(a)
}
}
var f1 = F1 ()
function F2 (fn) {
var a = 200
fn()
}
F2(f1)
- 返回值是函数
function F1 (){
var a = 100
return 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);
}