美文网首页
Js闭包面试解答

Js闭包面试解答

作者: working_Poor | 来源:发表于2018-12-28 18:40 被阅读0次

面试基本都会问到的问题,面试题基本都会有的一项问题

1、例子
<body onload="onMyLoad()">
    <p>产品一</p>
    <p>产品二</p>
    <p>产品三</p>
    <p>产品四</p>
    <p>产品五</p>
</body>

(1) 需求 : 每次点击对应目标时弹出对应的index( 0~4)

function onMyLoad(){
    var arr = document.querySelectorAll('p')
    for(var i = 0, len = arr.length; i < len; i++) {
        arr[i].onclick = function(){
          alert(i)
        }
    }
}

执行上面的代码,你会发现每次弹出的都是5。为什么会出现这种问题?

原因是i是全局变量,在你点击任意一项的时候,i的值已经变为了5,由于i是全局变量,所以,所有弹出的都是5

2、解决方案
  • 方案一 : 使用let 声明变量
 for(let i = 0; i < arr.length;i++){
    arr[i].onclick = function(){
         alert(i)
    }
}

原理 : 变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算(参见es6阮一峰)。本质就是 let 声明的变量具有块级作用域

  • 方案二 : 立即执行函数+闭包
for(var i = 0; i < arr.length;i++){
    arr[i].onclick = (function(){
        var j = i
        return function() {
            alert(j)
        }
    }())
}
for(var i = 0; i < arr.length;i++){
    arr[i].onclick = (function(i){
        return function() {
            alert(i)
        }
    }(i)) 
}
for(var i = 0; i < arr.length;i++){
    (function(i) {
        arr[i].onclick = function(){
            alert(i)
        } 
    }(i))    
}
for(var i = 0; i < arr.length;i++){
    (function() {
        var j = i;
        arr[i].onclick = function(){
            alert(j)
        }  
    }())    
}

原理 : 上边的四种方法其实就是一种方法。在一个函数中返回另一个函数,并且返回的函数中引用到了父函数作用域中的变量,则该变量不会被自动回收。外部函数还有对此变量的引用。(语言表达能力欠佳,可以参考犀牛书闭包章节,讲的很清楚)

  • 方案三 : 单独设置属性
for(var i = 0; i < arr.length;i++){
    arr[i].i = i;
    arr[i].onclick = function(){
        alert(this.i)
    }     
}

原理 : 为数组的每个元素单独设置对应的属性,此属性是唯一的,不会再是全局变量

  • 方案四 : 通过bind()方法实现
function f(i) {
   alert(i)
}
for(var i = 0; i < arr.length;i++){
        arr[i].onclick = f.bind(null,i)
}

原理 : 通过f.bind(),将f包装返回一个新的函数。 (解释的不行,其实还是闭包的应用,因为bind()方法就是使用闭包实现的)参见下面bind()简单的实现,你就明白了: 在执行f.bind(null, i)的时候,参数传入了闭包函数中,并且返回了一个函数,且返回的这个函数引用到了父函数中的boundArgs(这里面就包含了当前的i)变量,因此在返回函数后,此变量不会被垃圾回收机制回收,在返回的函数中还可以正常引用到boundArgs(这里面就包含了当前的i)。

Function.prototype.fbind = function(obj, /*args*/) {
    let self = this,
        boundArgs = arguments;
    return function() {
        let args = [],
            i;
        for(i = 1, len = boundArgs.length; i < len; i++){args.push(boundArgs[i])};
        for(i = 0, len = arguments.length; i < len; i++) {args.push(arguments[i])};
        return self.apply(obj, args)
    }
}
  • 方案五 : 通过Function实现(用到的不多)
for(var i = 0;i<arr.length;i++){
    arr[i].onclick = new Function("alert("+i+");");//每 new 一个 Function 得到一个 Function 对象(一个函数),有自己的闭包域
}

解释一下上面函数 : 通过 new 使用 Function 的构造函数 创建 Function 实例实现,由于传入的函数体的内容是字符串,故 Function 得到的是一个字符串拷贝,而没有得到 i 的引用(这里是先获取 i.toString()然后与前后字符串拼接成一个新的字符串,Function 对其进行反向解析成 JS 代码

3、 补充一个常见的面试题
//方案一
for (var i = 0; i < 5; i++) {
    setTimeout( (function timer(i) {
        return function() {
            console.log(i);
        }
    }(i)), 0 );
}
//方案二
for (var i = 0; i < 5; i++) {
    (function(i) {
        setTimeout( function() {
            console.log(i);
        }, 1000);
    }(i))
}
......
4、补充一个常见的面试题
<p id="help">Helpful notes will appear here</p>
<p>E-mail: <input type="text" id="email" name="email"></p>
<p>Name: <input type="text" id="name" name="name"></p>
<p>Age: <input type="text" id="age" name="age"></p>

<script type="text/javascript">
    function showHelp(help) {
        document.getElementById('help').innerHTML = help;
    }
    function setupHelp() {
        var helpText = [
            {'id': 'email', 'help': 'Your e-mail address'},
            {'id': 'name', 'help': 'Your full name'},
            {'id': 'age', 'help': 'Your age (you must be over 16)'}
        ];

        /*错误代码*/
        for (var i = 0; i < helpText.length; i++) {
            var item = helpText[i];
            document.getElementById(item.id).onfocus = function() {
                showHelp(item.help);
             }
        }


        // 解决方案一
        for (var i = 0; i < helpText.length; i++) {
            (function() {
                var item = helpText[i];
                document.getElementById(item.id).onfocus = function() {
                    showHelp(item.help);
                }
            }())
        }


        // 解决方案二
        for (var i = 0; i < helpText.length; i++) {
            var item = helpText[i];
            document.getElementById(item.id).onfocus = ceshi(item.help)
        }
        function ceshi(item) {
            return function() {
                showHelp(item)
            }
        }
        // or
        for (var i = 0; i < helpText.length; i++) {
            var item = helpText[i];
            document.getElementById(item.id).onfocus = (function(item) {
                return function() {
                    showHelp(item.help);
                }
            }(item))
        }
      

        //解决方案三
        for (var i = 0; i < helpText.length; i++) {
            let item = helpText[i];
            document.getElementById(item.id).onfocus = function() {
                showHelp(item.help);
            }
        }


        // 解决方案四
        for (var i = 0; i < helpText.length; i++) {
            var item = helpText[i];
            document.getElementById(item.id).onfocus = showHelp.bind(null, item.help)
        }
    }
    setupHelp();
</script>

相关文章

  • Js闭包面试解答

    面试基本都会问到的问题,面试题基本都会有的一项问题 1、例子 (1) 需求 : 每次点击对应目标时弹出对应的ind...

  • php之闭包函数(Closure)

    php闭包函数(Closure) JS闭包 js和php闭包使用和区别

  • JS闭包

    JS闭包 闭包练习

  • js闭包和命名空间总结

    js的闭包和命名空间在平常用的还是蛮多的,尤其是面试的时候经常会问,这里对js闭包和命名空间做个总结。 1. js...

  • 好程序员web前端培训分享web前端面试题JS篇之闭包

    好程序员web前端培训分享web前端面试题JS篇之闭包,JS中关于闭包的相关知识。如果你想参加web前面工作,那么...

  • javascript复习笔记(2)

    闭包 网上讲闭包的文章一搜一大把。而且面试时,比较传统的问题都有很大几率提到闭包的问题。的确,闭包是js中一个很重...

  • 理解js闭包

    如果你学JavaScript已经有一段时间了,你一定听过js闭包。这也是前端面试非常喜欢问的问题,所以理解js闭包...

  • JS闭包问题(二)

    在之前的JS闭包问题(一)文章中大概介绍了一下JS闭包,同时讲了闭包与变量之间的问题,今天我们继续聊闭包,聊聊闭包...

  • JS闭包大结局(JS闭包系列3)

    在上一篇中再谈JS闭包(JS闭包系列2),我详细的介绍了JS中的变量作用域相关的概念,结合第一节关于JS闭包(JS...

  • JS闭包入门

    最近有看到朋友的面经里提到的JS闭包的问题,就想研究研究,以下是我对JS闭包的简单理解。 到底什么是JS闭包? 定...

网友评论

      本文标题:Js闭包面试解答

      本文链接:https://www.haomeiwen.com/subject/kehelqtx.html