闭包
作用域
- 函数内部可以使用全局变量。
- 函数外部不可以使用局部变量
- 当函数执行完毕,本作用域内的局部变量会被销毁。
函数分为两个阶段
-
定义阶段
会在堆内存中开辟一个新的空间,将函数中的代码作为字符串存储进去。并将这个新空间的地址返回给一个变量。
-
调用阶段
在执行空间中开辟一个新的空间,执行函数中的代码,声明新的变量,执行完代码后,该空间会被销毁,变量也会被销毁。
什么是闭包
有权访问另外一个函数作用域中的变量的函数。
闭包的特点:
- 函数嵌套函数
- 内部函数引用外部函数的变量。
<script>
var n = 10;
var show = function() {
var n2 = 20;
function son() {
var n3 = 30;
console.log(n2);
}
return son;
};
var fn = show();
console.log(fn);
// ƒ son() {
// var n3 = 30;
// console.log(n2);
// }
</script>
闭包的作用
内存管理机制:
当有变量指向了一块内存地址时,因为随时可能会被调用,所以这块内存不会被销毁。
-
可以读取函数内部的变量
-
可以让这些变量的值始终保存在内存中。
-
将变量或者对象进行私有化。
function person(name){ var name = name; function sayName(){ console.log(name); } return sayName; } var fun = person("小明"); fun(); //小明
循环注册点击事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
button {
font-size: 18px;
}
</style>
<script>
window.onload = function() {
var btns = document.querySelectorAll("button");
for (var i = 0; i < btns.length; i++) {
btns[i].onclick = btnClick(i);
// 相当于下面的代码。
// btns[i].onclick = function() {
// alert(i);//结果5
// }
// btns[0] => alert(0)
// btns[1] => alert(1)
}
function btnClick(i) {
return function() {
alert(i);
}
}
}
</script>
</head>
<body>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
</body>
</html>
return和闭包区别
闭包可以保护里面的东西
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function show() {
var obj = {
name: "提莫",
price: 6300
}
return obj;
}
var tm = show();
tm.price = 0;
// console.log(tm);
//Object
// name: "提莫"
// price: 0
// __proto__: Object
function show2() {
var obj = {
name: "提莫",
price: 6300
}
function getPrice() {
return obj.price;
}
function setPrice(price) {
if (price < 4800) {
alert("该价格不可更改!")
} else {
obj.price = price;
alert(price)
}
}
return {
getPrice: getPrice,
setPrice: setPrice
}
}
var tm2 = show2();
tm2.setPrice(4801); //4801
console.log(tm2.getPrice);
//ƒ getPrice() {
// return obj.price;
// }
</script>
</body>
</html>
闭包的缺点
容易造成内存泄露。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
width: 100px;
height: 100px;
background-color: brown;
font-size: 22px;
line-height: 100px;
text-align: center;
margin: 100px;
}
</style>
<script>
window.onload = function() {
let divs = document.querySelectorAll("div");
divs.forEach(function(item) {
item.addEventListener("click", function() {
console.log(this.innerHTML);
// console.log(item.innerHTML);不用item,使用item会形成闭包
// console.log(this);
})
})
}
</script>
</head>
<body>
<div>云梦山</div>
<div>凤凰山</div>
</body>
</html>
闭包中的this
this对象是在运行时基于函数的执行环境绑定的,谁调用this就是谁。如果在全局范围中,this就是window,如果在对象内部,this就指向这个对象。
因为闭包并不属于这个对象的属性或方法。所以在闭包中的this是指向window的
<script>
let tm = {
user: "提莫",
get: function() {
let _this = this; //改变this指向
return function() {
console.log(_this);
return _this.user;
}
}
}
let a = tm.get();
console.log(a());//window
//{user: "提莫", get: ƒ}
// 提莫
</script>
<script>
let tm = {
user: "提莫",
get: function() {
return () => {
return this.user;
}
}
}
let a = tm.get();
console.log(a()); //提莫
</script>