248 闭包:概念,作用,案例,思考题案例,chrome 中调试闭包

Posted jianjie

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了248 闭包:概念,作用,案例,思考题案例,chrome 中调试闭包相关的知识,希望对你有一定的参考价值。

5.1 变量的作用域复习

变量根据作用域的不同分为两种:全局变量和局部变量。

  1. 函数内部可以使用全局变量。
  2. 函数外部不可以使用局部变量。
  3. 当函数执行完毕,本作用域内的局部变量会销毁。

5.2 什么是闭包

闭包(closure):指有权访问另一个函数作用域中的变量的函数。

简单理解就是 ,一个作用域可以访问另外一个函数内部的局部变量。

【被访问的局部变量所在的函数,就是闭包函数】

技术图片

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <script>
        // 闭包(closure)指有权访问另一个函数作用域中变量的函数。
        // 闭包: 我们fun 这个函数作用域 访问了另外一个函数 fn 里面的局部变量 num
        // 被访问的局部变量所在的函数,就是闭包函数
        function fn() {
            var num = 10;

            function fun() {
                console.log(num);
            }
            fun();
        }
        fn();
    </script>
</body>

</html>

5.3 在 chrome 中调试闭包

  1. 打开浏览器,按 F12 键启动 chrome 调试工具。
  2. 设置断点。
  3. 找到 Scope 选项(Scope 作用域的意思)。
  4. 当我们重新刷新页面,会进入断点调试,Scope 里面会有两个参数(global 全局作用域、local 局部作用域)。
  5. 当执行到 fn2() 时,Scope 里面会多一个 Closure 参数 ,这就表明产生了闭包。

5.4 闭包的作用

提问:我们怎么能在 fn() 函数外面访问 fn() 中的局部变量 num 呢 ?

作用:延伸变量的作用范围。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <script>
        // 闭包(closure)指有权访问另一个函数作用域中变量的函数。
        // 一个作用域可以访问另外一个函数的局部变量 
        // 我们fn 外面的作用域可以访问fn 内部的局部变量
        // 闭包的主要作用: 延伸了变量的作用范围
        function fn() {
            var num = 10;
            // function fun() {
            //     console.log(num);
            // }
            // return fun;

            return function() {
                console.log(num);
            }
        }
        var f = fn();
        f();
        // 类似于
        // var f = function() {
        //         console.log(num);
        //     }

        // var f =  function fun() {
        //         console.log(num);
        //     }
    </script>
</body>

</html>

5.5 闭包的案例

1、利用闭包的方式得到当前li 的索引号

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <ul class="nav">
        <li>榴莲</li>
        <li>臭豆腐</li>
        <li>鲱鱼罐头</li>
        <li>大猪蹄子</li>
    </ul>
    <script>
        // 闭包应用-点击li输出当前li的索引号
        // 1. 我们可以利用动态添加属性的方式
        var lis = document.querySelector('.nav').querySelectorAll('li');
        for (var i = 0; i < lis.length; i++) {
            lis[i].index = i;
            lis[i].onclick = function() {
                // console.log(i);
                console.log(this.index);

            }
        }
        // 2. 利用闭包的方式得到当前小li 的索引号
        for (var i = 0; i < lis.length; i++) {
            // 利用for循环创建了4个立即执行函数
            // 立即执行函数也成为小闭包因为立即执行函数里面的任何一个函数都可以使用它的i这变量
            (function(i) {
                // console.log(i);
                lis[i].onclick = function() {
                    console.log(i);

                }
            })(i);
        }
    </script>
</body>

</html>

2、闭包应用-3秒钟之后, 打印所有li元素的内容

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <ul class="nav">
        <li>榴莲</li>
        <li>臭豆腐</li>
        <li>鲱鱼罐头</li>
        <li>大猪蹄子</li>
    </ul>
    <script>
        // 闭包应用-3秒钟之后,打印所有li元素的内容
        var lis = document.querySelector('.nav').querySelectorAll('li');
        for (var i = 0; i < lis.length; i++) {
            console.log(i);
            // 先创建好 4 个 同步任务的立即执行函数,3秒后,再执行 这 4 个 同步任务的立即执行函数
            (function(i) {
                // console.log(i);
                setTimeout(function() {
                    console.log(lis[i].innerHTML);
                }, 3000)
            })(i);
        }
    </script>
</body>

</html>

3、闭包应用-计算打车价格

/*需求分析
打车起步价13(3公里内),  之后每多一公里增加 5块钱.  用户输入公里数就可以计算打车价格
如果有拥堵情况,总价格多收取10块钱拥堵费*/

 var car = (function() {
     var start = 13; // 起步价  局部变量
     var total = 0; // 总价  局部变量
     return {
       // 正常的总价
       price: function(n) {
         if (n <= 3) {
           total = start;
         } else {
           total = start + (n - 3) * 5
         }
         return total;
       },
       // 拥堵之后的费用
       yd: function(flag) {
         return flag ? total + 10 : total;
       }
    }
 })();
console.log(car.price(5)); // 23
console.log(car.yd(true)); // 33

5.6 思考题案例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <script>
        // 思考题 1:
        var name = "The Window";
        var object = {
            name: "My Object",
            getNameFunc: function() {
                return function() {
                    return this.name;
                };
            }
        };

        console.log(object.getNameFunc()()); // The Window
        // var f = object.getNameFunc();  
        // // 类似于
        // var f = function() {
        //     return this.name;
        // }
        // f();


        // 思考题 2:
        var name = "The Window";  
        var object = {    
            name: "My Object",
            getNameFunc: function() {
                var that = this;
                return function() {
                    return that.name;
                };
            }
        };
        console.log(object.getNameFunc()()); // My Object
    </script>
</body>

</html>

以上是关于248 闭包:概念,作用,案例,思考题案例,chrome 中调试闭包的主要内容,如果未能解决你的问题,请参考以下文章

前端面试基本---闭包大透析(包含案例及题目)

闭包的讲解及点赞的案例

JS闭包理解

闭包经典案例留存

闭包经典案例留存

闭包经典案例留存