JS面试经典题

闭包经典题:

1.

 执行结果:5 5 6 7 8 9

JS单线程执行机制问题:先执行执行栈中的同步任务,遇到异步函数就放入消息队列中等待,同步任务执行完毕,再按顺序将异步任务放入执行栈中继续进行。

执行栈内为同步任务即for循环的i++和log函数,将for循环内部的异步任务setTimeout放入消息队列,由于for循环则进行了五次内部的log(i++)放入消息队列中。

开始先从执行栈中进行,先进行五次i++,在输出i即5。再进行五次异步的定时器内的输出i++,即5,6,7,8,9。

 

2.利用闭包实现循环点击按钮打印索引:

思路:闭包+立即执行函数

<body>
    <ul class="nav">
        <li>A</li>
        <li>B</li>
        <li>C</li>
        <li>D</li>
    </ul>
    <script>
        let lis = document.querySelector('.nav').querySelectorAll('li');
        // 利用闭包实现
        for (var i = 0; i < lis.length; i++) {
            // 利用for循环创建了四个立即执行函数
            // 立即执行函数也称为小闭包,立即执行函数中的任意一个函数都能使用它的变量
            (function (i) {
                // 闭包产生
                lis[i].onclick = function () {
                    console.log(i);
                }
            })(i);
        }
    </script>
</body>

采取立即执行函数,解决异步问题。

如果不使用立即执行函数,内部点击事件是异步任务,会等到for循环结束完毕才从消息队列中回到执行栈,此时由于i变量声明是var,造成循环遍历泄露。导致i成为4,故点击时会报错,因为不存在下标为4的li。

立即执行函数和闭包搭配使用,在每次i遍历的时候,由于内部点击事件需要i故每次点击都会循环创建立即执行函数,又由于i的声明,产生了闭包。给立即执行函数赋值i,所以内部的点击事件可以访问到外部闭包中的i值,每次点击都会获取到对应的下标i,即达到所需的结果。

 

3.利用闭包实现3秒后打印所有li标签中的内容

思路:闭包+立即执行函数

<body>
    <ul class="nav">
        <li>A</li>
        <li>B</li>
        <li>C</li>
        <li>D</li>
    </ul>
    <script>
        // 3秒后打印所有li的内容
        let lis = document.querySelector('.nav').querySelectorAll('li');
        for (var i = 0; i < lis.length; i++) {
            (function (i) {
                setTimeout(() => {
                    console.log(lis[i].innerHTML);
                }, 3000);
            })(i);
        }
    </script>
</body>

如果贸然使用setTimeout延迟函数去打印lis[i]的innerHTML值,此时会因为延迟函数是异步任务的问题,等到循环结束后才打印i下标的li的内容,此时i变为4,故不合法。

故采用立即执行函数,循环的同时创建了立即执行函数并执行,访问到了i值即闭包。

 

4.利用闭包实现出租车计价问题

题目:打车价起步13(3公里内),之后每多一公里加收5块钱,用户输入公里数即可计算打车价格,若有拥堵情况,多收10元拥堵费

<script>
        // 打车价起步13(3公里内),之后每多一公里加收5块钱,用户输入公里数即可计算打车价格,若有拥堵情况,多收10元拥堵费
        let km = prompt('请输入公里');
        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;
                }, //正常总价
                mess: function(flag){
                    return flag ? total + 10 : total;
                } //拥堵费用
            }
        })();
    </script>

声明了一个立即执行函数car,并采用高阶函数的方式返回一个函数对象price和mess,分别计算正常总价和拥堵时的费用。此时由于start和total是局部变量的问题,故会产生闭包,在进行价格的计算后,由于闭包的存在,变量total不会被清理,在进行mess的判断时依然可以被访问到。

 

5.思考下列函数的执行结果:

<script>
        var name1 = 'The window';
        var object1 = {
            name: 'My Object',
            getNameFunc: function() {
                return function() {
                    return this.name1;
                }
            }
        }
        console.log(object1.getNameFunc()());
    
        var name2 = 'The window';
        var object2 = {
            name: 'MyObject',
            getNameFunc: function() {
                var that = this;
                return function() {
                    return that.name2;
                }
            }
        }
        console.log(object2.getNameFunc()());
    </script>

答:‘The window’和‘MyObject’

解释:第一个函数由于执行输出this的name,由于是匿名函数,故this指向window,则window下的name1为the window,第二个函数由于that存储了object2对象,存在闭包,故输出that的name为object2的name为MyObject

posted @ 2022-09-06 19:27  HM-7  阅读(63)  评论(0)    收藏  举报