JavaScript 闭包

前端 · 2020-08-14 ·

1 变量作用域

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

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

2 什么是闭包

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

简言之:一个作用域可以访问另一个函数内部的局部变量。也就是说如果一个函数的局部变量别的作用域(全局作用域、局部作用域)都可以访问到这个局部变量,此时就会有闭包产生,那么这个变量所在的函数,我们称这个函数为闭包函数。

    // 闭包(closure)指有权访问另一个函数作用域中变量的函数
    // 闭包:我们fun 这个函数作用域 访问了另外一个函数
    function fn() {
        var num = 10;
        function fun() {
            console.log(num);
        }
        fun();
    }
    fn();
    // 闭包的强大:fn外部的作用域访问fn 内部的局部变量
    // 闭包的主要作用:延伸了变量的作用范围,理论上函数执行后,局部变量就会销毁,但是这里 fun 函数调用了 fn的局部变量,
    // 因此num这时候还没有到销毁的时候,因为其他函数还需要调用它,等所有函数调用完后,再销毁。
    // 全局作用域访问函数局部作用域的例子如下。
    function fn() {
        var num = 10;
        // function fun() {
        //     console.log(num);
        // }
        // return fun;
        return function() {
            console.log(num);
        }
    }
    var f = fn();
    // 以上操作类似于
    // var f = function fun(){
    //     console.log(num);
    // }
    // or 以上操作类似于
    // var f = function (){
    //     console.log(num);
    // }
    f();

3 闭包的应用

3.1 循环注册点击事件:点击对应的li 输出对应的索引值我们可以利用动态添加属性的方式

3.1.1 我们可以利用动态添加属性的方式

    <ul class="nav">
        <li>赵</li>
        <li>钱</li>
        <li>孙</li>
        <li>李</li>
    </ul>
    <script>
        var lis = document.querySelector('.nav').querySelectorAll('li');
        // 1. 我们可以利用动态添加属性的方式
        for (var i = 0; i < lis.length; i++) {
            lis[i].index = i;
            lis[i].onclick = function() {
                console.log(this.index)
            }
        }
    <script>>  

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

    <ul class="nav">
        <li>赵</li>
        <li>钱</li>
        <li>孙</li>
        <li>李</li>
    </ul>
    <script>
        var lis = document.querySelector('.nav').querySelectorAll('li');
        // 2. 利用闭包的方式得到当前的li的索引号
        for (var i = 0; i < lis.length; i++) {
            // 利用for循环创建了4个立即执行函数,这里产生了闭包函数closurez(此处可省略名称)
            // onclick事件的函数访问了closurez函数的局部变量i
            // 立即执行函数也可以成为小闭包
            // 立即执行函数里面的任何一个函数都可以使用它的i变量
            (function closurez(i) {
                lis[i].onclick = function() {
                    console.log(i)
                }
            })(i);
        }
    <script>

3.2 循环中的setTimeout()

    <ul class="nav">
        <li>赵</li>
        <li>钱</li>
        <li>孙</li>
        <li>李</li>
    </ul>
    <script>
        var lis = document.querySelector('.nav').querySelectorAll('li');
        // 1. 利用闭包-3s之后,打印所有li元素的内容
        for (var i = 0; i < lis.length; i++) {
            (function(i) {
                setTimeout(function() {
                    console.log(lis[i]);
                }, 3000);
            })(i);
        }
    <script>

3.3 闭包应用:计算外卖快递服务费

    // 闭包应用:计算外卖快递费
    // 假设外卖起送价10元(默认2份以内),每超过一份再增加2元,用户输入外卖数量
    // 平台活动满20可用5元外送券
    // 可通过闭包将延长局部变量销毁,将局部变量挂起,等待其他函数调用。
    var car = (function() {
        var start = 10; //
        var total = 0;
        return {
            price: function(n) {
                if (n <= 2) {
                    total = start;
                    return total;
                } else {
                    total = start + 2 * (n - 2);
                    return total;
                }
            },
            sale: function() {
                return total > 20 ? total - 5 : total;
            }
        }
    })();
    console.log(car.price(10));
    console.log(car.sale());
下一篇:
%