- 闭包:理解关键--作用域
闭包是引用了自由变量的函数,这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另外一种说法认为闭包是由函数和其相关的引用环境组合而成。
闭包和普通函数的直接区别就在于实现了信息的驻留。普通函数在执行完成后会释放掉局部变量。
特点/ 好处: 实现了信息的驻留(信息的保持,引用依旧存在,空间不销毁)
简单的闭包:
var Person = function() {
var count = 0;
return function() {
console.log( count++ )
}
}
//形式二
var Person = !function() {
var count = 0;
return funtion() {
console.log( count++ )
}
}()
console.log(Person()); //ƒ(){ console.log( count++ ) } 注意打印的形式
var p = Person();
p(); //0
p(); //1
p(); //2
解析:关键词--作用域、 EC
[[GEC,VO:{p:new Person,Person}], [EC,AO:{count=0}]] ,函数创建完成,浏览器执行环境栈压入全局执行环境(GEC)及VO; 第一次调用函数p(),再压入局部执行环境(EC)及AO,
执行console.log(count++),打印count,保存count+1(先输出,再自增),执行完成,释放这个EC;第二次调用函数p(),再重新压入一个EC及AO,return内部函数add(),此时count=1(信息的驻留),打印count,保存count+1(先输出,再自增),执行完成,释放这个EC。
应用 一
var arr = [{name: 'a1'},{name: 'a2'},{name: 'a3'}];
function fn() {
for(var i = 0; i < arr.length; i++) {
(function(num) {
arr[i].fun = function() {
alert(num);
}
})(i) //这里把i作为局部变量传入给num,保存了当前这个局部变量形成闭包
}
}
fn();
arr[0].fun(); //0
arr[1].fun(); //1
arr[2].fun(); //2
应用二 --封装
- 例 一、
//闭包隐藏数据,只提供API
function createCache() {
let data = {};
return{
set: function(key,val){
data[key] = val
},
get: function(key) {
return data[key]
}
}
}
var c = createCache()
c.set('a',100)
console.log(c.get('a'));
- 例二 、
(function() {
var num = 1234;
var outer = {};
function converter(x) {
return x;
}
outer.getNum = function() {
return converter(num)
}
window.outer = outer; //关键
})()
console.log(outer.getNum());
闭包的缺点:闭包导致内存会驻留,如果是大量对象的闭包环境注意内存消耗
在ES6中有块级作用的概念,用let 声明变量
var arr = [{name: 'a1'},{name: 'a2'},{name: 'a3'}];
function fn() {
for(let i = 0; i < arr.length; i++) {
arr[i].fun = function() {
alert(i);
}
}
}
fn();
arr[0].fun(); //0
arr[1].fun(); //1
arr[2].fun(); //2