要理解闭包须要先理解变量做用域javascript
明确几点:html
按照做用域区分,变量有全局变量和局部变量,因为做用域链,函数内部是能够直接读取全局变量的,而函数外部没法直接读取函数内的局部变量。java
「函数」和「函数内部能访问到的变量」(也叫环境)的总和,就是一个闭包。chrome
本质上,闭包就是将函数内部和函数外部链接起来的一座桥梁
浏览器
来看一个栗子bash
function fn(){
// default
var n=66;
// get
function getN(){
return n;
}
// set
function setN(num){
n=num;
}
// add
function addN(){
n++;
}
return {
getN:getN,
setN:setN,
addN:addN
}
}
var test=fn();
console.log(test.getN()); //66
test.setN(666);
console.log(test.getN()); // 666
test.addN();
console.log(test.getN()); // 667
复制代码
咱们经过fn暴露出来的接口访问到了函数内部的n
,同时咱们对n
的值作了修改,能够看到n依然是存在于内存中的。闭包
具体应用方面:函数
1)因为闭包会使得函数中的变量都被保存在内存中,在IE中可能致使内存泄露。解决方法是,在退出函数以前,将不使用的局部变量所有删除。ui
2)闭包会在父函数外部,改变父函数内部变量的值。因此,若是你把父函数看成对象(object)使用,把闭包看成它的公用方法(Public Method),把内部变量看成它的私有属性(private value),这时必定要当心,不要随便改变父函数内部变量的值。this
让咱们理论结合实(mian)践(shi)来理解如下闭包 如下皆为chrome浏览器环境运行的结果
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function() {
return function() {
return this.name;
};
}
};
console.log(object.getNameFunc()()); // The Window
复制代码
拆成两步就很容易看懂
var name = "The Window";
var object = {
name: "My Object",
getNameFunc: function() {
var that = this;
return function() {
return that.name;
};
}
};
console.log(object.getNameFunc()()); // My Object
复制代码
咱们一样分两步
上级
做用域寻找that
,也就是getNameFunc里面的that
,that=this
,此时的this指向调用getNameFunc
的对象object
。function foo(x) {
var tmp = 3;
function bar(y) {
console.log(x + y + (++tmp));
}
bar(10);
}
foo(2); //16
foo(2); //16
foo(2); //16
foo(2); //16
复制代码
这里只是函数调用哦,不是闭包哦
function foo(x) {
var tmp = 3;
return function (y) {
console.log(x + y + (++tmp));
}
}
var bar = foo(2);
bar(10); //16
bar(10); //17
bar(10); //18
bar(10); //19
复制代码
当你return的是内部function时,就是一个闭包。
一个函数访问了它的外部变量,那么它就是一个闭包
function fun(n,o) {
console.log(o)
return {
fun:function(m){
return fun(m,n);
}
};
}
var a = fun(0); // undefined
a.fun(1); // 0
a.fun(2); // 0
a.fun(3); // 0
复制代码
这题有点绕,咱们来分解一下:
a = fun(0)
等价于执行后,console.log(o)
没有在当前以及父级做用域中寻找到o,因此输出的是undefined
,同时a被赋值为{fun:function(m){return fun(m,0)}}
。a.fun(1)
执行,简化后为(function(1){return fun(1,0)})()
===fun(1,0)
,***当前做用域里面没有fun,最后找到了顶级的function fun(n,o)***,执行console.log(0)
function fun(n,o) {
console.log(o)
return {
fun:function(m){
return fun(m,n);
}
};
}
var b = fun(0).fun(1).fun(2).fun(3);
// undefined
// 0
// 1
// 2
复制代码
这链式看的我好慌,咱们继续分解一下
fun(0)
会输出o
,此时没有o因此为undefind
,同时fun(0)表达式执行结果为{fun:function(m){return fun(m,0)}}
(先忽略掉后面的fun(1)、fun(2)、fun(3))。fun(1)
等价于执行(function(1){return fun(1,0)})()
,继续输出o
,此时o为0
,表达式简化为{fun:function(m){ return fun(m,1)}}