闭包
闭包的概念:函数A里面有一个子函数B,函数B可以访问函数A中定义的变量或者数据,此时形成了闭包(通俗的说:函数里面嵌套一个函数(或者对象),里层的函数可以用外层函数的数据或方法)
闭包的模式:
1.函数模式的闭包:在一个函数中有一个函数
function fn(){
//声明变量
var num=10
//函数的声明
function f2(){
console.log(num)
}
//函数调用,调用fn的同时也会调用f2
f2();
}
fn()
2.对象模式的闭包:在一个函数中有一个对象
function fn() {
var num = 30
var obj = {
age: num
}
console.log(obj.age);
}
fn()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 随对象式的闭包:在一个函数中有一个函数
/* function fn() {
// 变量的声明
var num = 10
// 函数的声明,
function f2() {
console.log(num); 10
}
// 函数调用,调用fn的同时也调用f2
f2()
} */
// 对象模式的闭包:函数中有一个对象
/* function fn() {
var num = 30
var obj = {
age: num
}
console.log(obj.age); //30
} */
// 函数模式的闭包(简写)
/* function fn() {
var num = 20
// 调用fn,会返回一个匿名函数
return function() {
console.log(num);
return num
}
}
// ff获取到的就是fn中return的一个匿名函数
var ff = fn()
// 调用匿名函数
// ff() 20
// res获取到的是fn中的匿名函数return的数据:num,这里得到的是数据而不是函数,所以不能调用,只能输出
var res = ff()
console.log(res); //20 */
// 对象模式的闭包(简写)
function fn() {
var num = 30
// 调用fn,返回的是一个对象
return {
age: num
}
}
// 获取到是一个对象
var res = fn()
console.log(res.age); //30
</script>
</body>
</html>
特点**:
1.让外部访问函数内部变量成为可能
2.局部变量会常驻内存中
3.可以避免使用全局变量,防止全局变量污染
4.造成内存泄漏(缺点)
内存泄漏:有一块内存空间被长期占用,而不被释放
闭包的作用:可以缓存数据,可以延长作用域链
缓存数据是闭包的优点也是缺点,因为数据没有得到及时的释放,会一直占用内存空间
局部变量是在函数的作用域内有效,放函数执行结束,局部变量就会自动的释放
而使用闭包后。函数里面的局部变量的使用作用域链就会得到延长
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// function fn() {
// var num = 10
// function fn2() {
// console.log(num);
// }
// fn2()
// }
// function fn() {
// var num = 20
// var obj = {
// num: num
// }
// console.log(obj.age)
// }
/* function fn() { var num = 20
// 返回的是一个方法
return function()
{
console.log(num) return num
}
}
// fn()执行的是fn这个函数
// fn()()是调用fn里面的匿名函数
var aa=fn() aa() //20*/
/* function fn() {
var num = 100
return { age: num } }
console.log(fn().age) 100*/
/* function fn() {
var num =100
num++
return num
}
// 函数一执行完,就释放了,后面调用的都是重新从初始化开始执行,所以结果都是11
console.log(fn()) //11
console.log(fn()) //11
console.log(fn()) //11 */
/* function fn() {
var num = 10
return function() {
num++
return num
}
}
var ff = fn() */
function fn() {
// num在fn方法的作用域里面是全局的
var num = 10
// 只要这个匿名函数不消失,fn函数也不消失,但是页面一刷新,函数就被重置
return function() {
num++
return num
}
}
var f = fn()
// f()调用的是fn里面匿名函数
console.log(f()); //11
console.log(f()); //12
console.log(f()); //13
</script>
</body>
</html>
闭包案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 普通函数
/* function fn() {
var num = 20
num++
// 调用fn就返回num
return num
}
// 普通函数一执行完就释放内存,所以结果都初始值21
console.log(fn()); //21
console.log(fn()); //21
console.log(fn()); //21 */
// 函数模式的闭包
function fn() {
// 这个num只在fn的作用域内有效
var num = 30
// 调用fn就返回一个匿名函数
// 调用匿名函数后,这个num就被缓存在内存中(闭包的作用:缓存数据)
return function() {
num++
return num
}
}
// res是fn返回的匿名函数
var res = fn()
// 输出的是调用fn中的匿名函数所返回的结果,这里匿名函数中的num是缓存中num,而不是调用fn函数得到的num,而页面一刷新,缓存就没了,num也成立初始值30
console.log(res()); //31
console.log(res()); //32
console.log(res()); //33,到这里,
</script>
</body>
</html>
变量只定义未赋值,输出就是undefined,不声明就使用会报错
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function randNum() {
// 获取1-10的随机数
var num = parseInt(Math.random() * 10 + 1) //0-9,再加1,就是1-10
console.log(num);
}
// randNum()
// 刷新一次,就会重新获取
function fn() {
var num = parseInt(Math.random() * 10 + 1)
return function() {
console.log(num);
}
}
// ff得到的是一个匿名函数
var ff = fn()
// 下面的都是调用fn里面的匿名函数,并没有调用fn,所以num值不变
ff()
ff()
ff()
ff()
</script>
</body>
</html>
闭包案例-产生随机数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 普通函数方式
/* function showNum() {
// Math.random()随机得到的是[0,1)之间的小数(包括0,不包括1)
// parseInt(Math.random() * 10):随机[0,10)之间的整数
// 再加1,就是随机得到[1,10]
var num = parseInt(Math.random() * 10) + 1
console.log(num);
}
// 得到的四个数都是不同的
showNum();
showNum();
showNum();
showNum(); */
// 闭包的方式,多次调用函数的到的随机数都是相同的
function showNum() {
var num = parseInt(Math.random() * 10) + 1
// 闭包将num放入缓存
return function() {
// 这里输出的是缓存中的num
console.log(num);
}
}
// res是showNum中的匿名函数
var res = showNum()
// 得到的随机数都是相同的,都是缓存中num
res()
res()
res()
res()
</script>
</body>
</html>
闭包点赞小案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
ul {
list-style-type: none;
}
li {
float: left;
margin-left: 10px;
}
div {
width: 200px;
height: 180px;
background-color: dodgerblue;
}
input {
margin-left: 30%;
}
</style>
</head>
<body>
<ul>
<li>
<div></div><br/><input type="button" id="one" value="赞1"></li>
<li>
<div></div><br/><input type="button" value="赞1"></li>
<li>
<div></div><br/><input type="button" value="赞1"></li>
<li>
<div></div><br/><input type="button" value="赞1"></li>
</ul>
<script>
// 获取到input
var btns = document.querySelectorAll('input')
// 循环
for (let i = 0; i < btns.length; i++) {
//写的是fn(),所以已经调用了fn函数,所以点击时,触发的是fn里面的匿名函数
btns[i].onclick = fn()
}
function fn() {
var num = 1
//使用闭包,将num放入缓存,点击是匿名函数
// 这里面num一旦使用就一直存在内存里面,一刷新会释放,而重新从1开始
return function() {
num++
this.value = "赞(" + num + ")"
}
}
</script>
</body>
</html>