闭包
作用域
要理解闭包,首先必须理解Javascript特殊的变量作用域。
变量的作用域无非就是两种:全局变量和局部变量。 Javascript语言的特殊之处,
就在于函数内部可以直接读取全局变量。我们有时候需要得到函数内的局部变量值。。
因此我们可以用函数套函数,并返回里面的函数来访问外层函数内部的变量,
什么是闭包
闭包是指有权访问另一个函数作用域中的变量的函数,
创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量
闭包的特点和优点
闭包的特点
1.函数嵌套函数
2.函数内部可以引用外部的参数和变量
3.参数和变量不会被垃圾回收机制回收
闭包的优点
1.希望一个变量长期驻扎在内存中
2.避免全局变量的污染
3.私有成员的存在
嵌套函数的闭包
定义的函数fun1,里面有一个sum,前面我们说过return是可以返回任何值得,
包括函数,因此在该案例中我们直接返回一个function函数,这样的写法等同于右图。同样嵌套执行以后,
因为fun1这个函数执行后保存为了变量fun2,也就是说fun2就是fun1内部那个匿名函数,
因此在执行fun2后就执行了一次fun1中的那个匿名函数,fun2是被保存到了外部变量,
所以函数运行完后sum并没有被清理掉,因为外面有对于这个匿名函数的引用,因此,再次执行时,sum被继续连加。
直到最后fun2被赋值为null的时候,fun1当中的匿名函数引用才被切断,这时候也把这个sum清理掉了。
function fun1(){
var sum=1;
return function(){
sum++;
return sum;
}
}
var fun2=fun1();
console.log(fun2());//2
console.log(fun2());//3
闭包内的作用域
fun1是作为一个自执行函数返回定义的,因此fun1实际上是返回的对象,而对象下有一个方法sum,
因此fun1.sum就是调用该对象下的sum方法,注意,a是自执行函数的
私有变量,b是对象的共有属性,因此,调用b的时候this.b可以在对象内调用,
也可以在外部使用this.b调用,但是在外部是无法调用变量a的,因为他是局部变量。
var fun1=(function(){
var a=3;
return {
b:7,
sum:function(){
return this.b+a;
}
}
})()
console.log(fun1.sum());//10
柯里化函数
柯里化函数利用了闭包的特点,传入的参数会做存储留用,等到参数传完了,再对参数做处理。
案例一:点击文档中的六个按钮,当所有按钮都点击完之后弹出对话窗。
思路,给每个按钮增加index属性,每次点击执行函数all返回的函数,将每个按钮的index存储到对象中,
如果有就不存储,然后设置累加器,存储就累加,当累加到6即存储完毕,然后弹出对话窗。
var buttons=document.querySelectorAll("button")
for(var i=0;i<buttons.length;i++){
buttons[i].addEventListener("click",clickHandle)
buttons[i].index=i+1+""
}
var a = all()
function clickHandle(e){
a(this.index)
}
function all(){
var obj={}
var counter=0
return function(index){
if(obj[index]) return
obj[index] = index
counter++
console.log(obj,counter)
if(counter===6){
alert("实验成功")
for(var key in obj){
delete obj[key]
}
counter=0
}
}
}
案例二:
运行一个函数,如果传参,将参数存储,如果不传参,将存储的参数累加并打印。
function curry(fn) {
var arg=[];
return function () {
if(arguments.length===0){
fn.apply(null,arg);
}else{
var arr=Array.from(arguments);
arg=arg.concat(arr);
}
}
}
function getSum() {
var arr=Array.from(arguments);
var sum=arr.reduce(function (sum,item) {
return sum+item;
});
console.log(sum);
}
var fn=curry(getSum);
fn(10);
fn(20);
fn(30);
fn();