一、闭包的作用
- JavaScript通过函数嵌套,使得内部函数可以访问定义在外部函数中的变量和函数,以及外部函数能够访问到的所有变量和函数。
但是外部函数无法直接访问定义在内部函数里的变量和函数,这样给内部函数的变量提供了安全性。 - 由于内部函数可以访问外部函数定义的变量和函数,所以在内部函数生存周期大于外部函数时,会延长外部函数中定义的函数和变量的生命周期(即让一些变量始终保持在内存中,不会在外部函数调用完成之后就被清除)。
二、闭包的用法
1.基本的闭包(嵌套函数形成闭包)
- 代码示例
function outerfunc(x){ var y=10 function innerfunc(z){ return x*y*z } return innerfunc }
- 运行结果
2.嵌套函数
-
说明
一个函数里面嵌套另一个函数,内部函数的对于外部函数来说时私有的(内部函数定义的变量和函数外部函数是不可见的),但是外部函数的参数和变量内部函数都是可以访问的。一个闭包是一个可以拥有独立的环境和变量的表达式(通常为函数)。 -
代码示例
function addSquares(a, b) { function square(x) { return x * x; } return square(a) + square(b); } a = addSquares(2, 3); // returns 13 b = addSquares(3, 4); // returns 25 c = addSquares(4, 5); // returns 41
内部函数square形成闭包,可以调用外部函数并给外部函数和内部函数指定参数
3.链式作用域
- 当多重嵌套时,内部函数会一层一层的继承外部函数的作用域
- 代码示例
function A(x) { return function B(y) {//继承x return function C(z) {//继承x,y console.log(x + y + z); } } } A(1)(2)(3); // 6
4.复杂的闭包示例
- 在下面这种情形中,返回了一个包含可以操作外部函数的内部变量方法的对象。
- 代码示例
var createPet = function(name) { var sex; return { setName: function(newName) { name = newName; }, getName: function() { return name; }, getSex: function() { return sex; }, setSex: function(newSex) { if(typeof newSex == "string" && (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) { sex = newSex; } } } } var pet = createPet("Vivie"); pet.getName(); // Vivie pet.setName("Oliver"); pet.setSex("male"); pet.getSex(); // male pet.getName(); // Oliver
三、使用闭包可能会出现的问题
1.命名冲突
-
未发生命名冲突的情况
- 代码示例
function outerfunc(){ var x=10 function innerfunc(){ return x*x; } return innerfunc }
- 运行结果
- 代码示例
-
发生命名冲突的情况
- 代码示例
function outerfunc(){ var x=10 function innerfunc(x){ return x*x; } return innerfunc }
- 运行结果
- 代码示例
-
对比两者代码和结果可知
- 当内部函数的参数和外部函数属性命名相同时,外部函数的属性将不会传递到内部函数内部
- 在后面这种方式时,需要给内部函数指定参数,方可正常调用
2.内存消耗
- 闭包会使函数的变量在内存中保存下来,如果滥用闭包会消耗大量内存,甚至还会产生大量的无效内存,产生网页性能问题。
参考
官方文档:
1.JavaScript函数