什么是闭包?
要理解闭包,首先必须理解Javascript特殊的变量作用域。
变量的作用域无非就是两种:全局变量和局部变量。
Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量(作用域链)。
//第一种
var t = 666;
function f1(){
console.log(t);
}
f1();
//第二种
function f2(){
var z = 777;
}
f2();
console.log(z)
//第三种
function f1(){
e=888;
}
f1();
console.log(e)
发现什么不同了吗?因为三者的变量作用域不一样。
针对第三种的特别说明
①变量前面没有用var声明;
②在变量所在在的作用域链中没有这个变量名称;
针对的错误定义:没有用var声明的为全局变量
//第四种
var d = 0;
function f4(){
var d = 1;
return function bar(){
d = 2;
}
}
f4();
console.log(n);
//第五种
var u = 0;
function f5(){
u = 1;
return function(){
var u = 2;
}
}
foo();
console.log(u);
所以关于闭包的定义:
函数内可以访问函数外部的变量,并且该函数及其执行上下文环境(作用域)共同构成!
从堆栈的角度看待
var a = 1
var b = {m: 20 }
b = { m:30}
闭包的作用
①读取函数内部的变量(访问私有变量)
function f6(value){
var name = value;
this.getName = function(){
return name
};
this.setName = function(){
name = value
}
}
var person = new Person('zhangsan');
console.log(person.getName());
person.setName('lisi');
console.log(person.getName());
②让这些变量的值始终保持在内存中。不会在调用后被自动清除。
③方便调用上下文的局部变量。利于代码封装(封装私有属性、方法)。
function f7() {
var sum = 0;
var obj = {
inc:function () {
sum++;
return sum;
}
};
return obj;
}
let result = f7();
④事件的回调
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试</title>
</head>
<body>
<a href="#" id="size-12">12</a>
<a href="#" id="size-20">20</a>
<a href="#" id="size-30">30</a>
<script type="text/javascript">
function changeSize(size){
return function(){
document.body.style.fontSize = size + 'px';
};
}
var size12 = changeSize(12);
var size14 = changeSize(20);
var size16 = changeSize(30);
document.getElementById('size-12').onclick = size12;
document.getElementById('size-20').onclick = size14;
document.getElementById('size-30').onclick = size16;
</script>
</body>
</html>
闭包会造成内存泄漏吗?
看待这个问题首先应该回顾什么是内存泄漏。
提到一个:垃圾回收机制:
- 如果一个对象不再被引用, 那么这个对象就会被垃圾回收机制回收;
- 如果两个对象互相引用, 且不再被第3者所引用;
- 那么这两个互相引用的对象也会被回收。 (在闭包中,父函数被子函数引用,子函数又被外部的一个变量引用,这就是父函数不被回收的原因);