JS中的闭包问题——对象模式,函数模式、内存泄漏

73 篇文章 0 订阅
18 篇文章 1 订阅

闭包

闭包的概念:函数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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值