function sayHello(name){ let str = 'Hello,${name}'; function say(){ console.log(str); } return say; } let myHello = sayHello('abby'); myHello();
上面的代码,在sayHello函数里面定义的say函数和这个函数声明的词法环境就造成了一个闭包。say函数引用了sayHello函数里面定义的一个变量str,而且sayHello函数将say这个函数return了出去,这样,在sayHello函数的外面也能访问到它词法做用域里面的变量str,最后就像say这个函数和str这个变量绑定了同样闭包
let myHello = sayHello('abby');
这段代码的时候,按理会销毁掉sayHello这个函数的执行环境,可是在这里却没有,由于,sayHello这个函数返回的是一个函数,这个函数里面的str引用了外部的变量str,若是销毁了sayHello的执行环境就会找不到了,因此,sayHello的执行环境会一直在内存中,因此也就会有闭包会增长内存开销的说法function createIncrementor(start) { return function () { return start++; }; } var inc = createIncrementor(5); inc() // 5 inc() // 6 inc() // 7
start是函数createIncrementor的内部变量,经过闭包,start的状态被保留了,每一次调用都是在上一次调用的基础上进行计算,闭包inc使得函数createIncrementor的内部环境一直存在,由于inc始终存在内存中,而inc的存在依赖于createIncrementor,所以该函数不会在调用结束后,被垃圾回收机制回收函数
function Person(name) { var _age; function setAge(n) { _age = n; } function getAge() { return _age; } return { name: name, getAge: getAge, setAge: setAge }; } var p1 = Person("xiaoming"); p1.setAge(25); pa.getAge(); //25
函数Person的内部变量_age,经过闭包getAge和setAge,变成了返回对象p1的私有变量,外层函数每次运行,都会产生一个新的闭包,而这个闭包又会保留外层函数的内部变量,内存也就消耗较多code
一、常见的闭包都是return出来一个函数,但并非说明,闭包必定须要return一个函数,return一个函数也只是为了能在做用域范围以外访问一个变量对象
let say; function sayHello(name){ let str = 'Hello,${name}'; say = function(){ console.log(str); } } let myHello = sayHello('abby'); say();
二、同一个调用函数生成同一个闭包环境,在里面声明的全部函数同时具备这个环境里面的变量的引用ip
let get,up,down function setUp(){ let number = 20; get = function(){ console.log(number); } up = function(){ number += 3; } down = function(){ number -= 2; } } setUp(); get(); up(); down(); get();
三、每个调用函数都会建立不一样的闭包环境,里面的变量互不影响内存
function newClosure(){ let array = [1,2]; return function(num){ array.push(num); console.log('array:${array}'); } } let myClosure = newClosure(); let yourClosure = newClosure(); myClosure(3); yourClosure(4); myClosure(5);
四、在循环里面建立闭包作用域
function newClosure(){ for(var i=0;i<5;i++){ setTimeout(function(){ console.log(i); }); } } newClosure();//5个5
改进方法一:建立一个新的闭包对象,这样每一个闭包对象里面的变量就互不影响rem
function log(i){ return function(){ console.log(i); } } function newClosure(){ for(var i=0;i<5;i++){ setTimeout(log(i)); } } newClosure();
每次log(i)都会建立不一样的闭包对象,全部的回调函数不会指向同一个环境get
改进方法二:使用自执行函数,外部的匿名函数会当即执行,而且把i做为它的参数,此时函数内变量e就拥有了i的一个拷贝。当传递给setTimeout的匿名函数执行时,它就拥有了对e的引用,而这个值是不会被循环改变的回调函数
function newClosure(){ for(var i=0;i<5;i++){ (function(e){ setTimeout(function(){ console.log(e); }); })(i) } } newClosure();