作用域分为三种:
- 全局作用域
- 函数作用域
- 块级作用(
es6
中的let/const
)
(一)闭包closure
闭包的作用:函数执行形成的私有作用域,保护里面的变量不受外界干扰的机制
闭包:自由变量的查找是在函数定义的地方,向上级的作用域查找,不是在执行的地方
题型一:
// 函数作为返回值
function create() {
const a = 100;
return function() {
console.log(a);
}
}
const fun = create();
const a = 200;
fun(); // 100
题型二:
// 函数作为参数被传递
function print(fun) {
const a = 200;
fun();
}
const a = 100;
function fun() {
console.log(a);
}
print(fun); // 100
只要把f2
作为返回值,就可在f1
外部读取它的内部变量,从而实现外部读取局部变量
function f1(){
var n = 999;
nAdd = function(){ n+=1 }
function f2 (){
alert(n);
}
return f2;
}
var result = f1();
result(); // 999
nAdd(); // 前面没用var定义,是全局变量,可直接调用
result(); // 1000
result实际上就是闭包f2()
函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1()
中的局部变量n
一直保存在内存中,并没有在f1()
调用后被自动清除。
原因在于f1()
是f2()
的父函数,而f2()
被赋给了一个全局变量,这导致f2()
始终在内存中,而f2()
的存在依赖于f1()
,因此f1()
也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
最大的用处是:
- 可以读取函数内部的变量
- 让这些变量的值始终保持在内存中
实际开发中闭包的应用
隐藏数据:cache工具
// 闭包隐藏数据,只提供API
function createCache() {
const data = {}; // 闭包周静的数据,被隐藏,不被外界访问
return {
set: function(key, val) {
data[key] = val;
},
get: function(key) {
return data[key];
}
}
}
const c = createCache();
c.set('a', 100);
console.log(c.get('a'))