定义
先来介绍一下闭包的定义。
闭包发生在创建函数时,实质是一个作用域,在该作用域中允许该自身函数访问并且操作该自身函数之外的变量。
举个例子:
<script>
var testVar = 123;
function testFunc(){
console.log(testVar)
}
testFunc();//123
</script>
执行上面的代码可以看到打印出123,在函数testFunc里面可以访问变量testVar,这个全局作用域就是一个闭包。其实我们在实际工作中经常会写这样的代码,只是对闭包界定不是很清楚,具体问起来也不知道怎么来解释闭包。这个栗子可能还不够清晰,那么再举一个:
<script>
var outerValue = '我是外部变量';
var later;
function outerFunction(){
var innerValue = '我是内部变量';
var innerFunction = function(){
console.log(outerValue);
console.log(innerValue);
};
later = innerFunction;
}
outerFunction();
later();
</script>
执行结果:
我是外部变量
我是内部变量
可能大家觉得外部函数outerFunction执行结束后,内部变量innerValue就消失了,但是实际上都打印出来了,这就是闭包的作用。在外部函数执行结束后,将内部函数innerFunction的引用复制给later,执行later相当于执行内部函数,但是仍然可以访问innerValue。
闭包的核心原则:
1,内部函数的参数是包含在闭包中的;
2,作用域之外的所有变量,即便是函数声明之后的那些声明,也都包含在闭包中;
3,在相同的作用域中,尚未声明的变量不能提前引用(变量提升)。
使用闭包
举栗子来说明在页面中如何使用闭包;
1,私有变量
闭包的一种常见用法就是封装一些信息作为私有变量,也就是说,限制这些变量的作用域。在编写面向对象的JS代码中,是无法使用传统的私有变量的,即无法让对象的属性保持对外隐藏。但是通过使用闭包就可以创建私有变量。
栗子:
<script>
function MyConstructor(){
var counter = 0;
this.getCounter = function(){
return counter;
}
this.addCounter = function(){
counter++;
}
}
var myConstructor = new MyConstructor();
myConstructor.addCounter();
console.log(myConstructor.getCounter());
console.log(myConstructor.counter);
</script>
执行结果:
1
undefined
不能直接访问私有变量counter,只能通过存取的方式获取私有变量的值。
闭包的优点
使用闭包实际上是在如何使用JS中的作用域特性。
1,利用闭包作用域特性可以将一些变量(函数也是变量)隐藏起来,实现私有化。为什么要隐藏呢?依据软件设计中的最小特权原则,应该最小限度的暴露必要内容,而将其他内容都隐藏起来,比如某个模块或者对象的API设计。如果所有变量和函数都在全局作用域中,当然可以在所有的内部嵌套作用域中都访问到它们。但是一句最小特权原则应该设法将其私有化。
2,规避冲突。像jQuery等第三方库都会妥善的将内部私有的函数和变量隐藏起来,防止在使用过程中如果有意或者无意使用了相同的变量名或者函数名引发冲突。
闭包缺点:
将函数片段用函数包含起来,首先会起一个函数名,这个函数名本身也就污染了所在的作用域;其次必须通过函数名调用才能运行其中的代码。解决方案:立即执行函数。用表达式将函数片段包起来,然后立即执行。这个函数名在所在作用域中不能被调用,它只被绑定在函数表达式自身的函数中。
网友评论