对于“输出十个10面试题”的理解

题目如下:

 var funcs = []
    for (var i = 0; i < 10; i++) {
        funcs.push(function() { console.log(i) })
    }
    funcs.forEach(function(func) {
        func()
    })

第一眼看到的时候以为会输出0~9,结果输出的是十个10,果然入坑了。。(小白的无知)于是在网上查了一下,发现与匿名函数,闭包,作用域等问题相关,下面就说一下我的理解。

首先得知道什么是匿名函数,以及它什么时候才会执行,参考于 https://www.cnblogs.com/ranyonsue/p/10181035.html

这里的  function() { console.log(i) })  就是一个匿名函数,它是不会自动执行的,除非给它加上括号,那么为什么会输出十个10呢?原因是后面的 func() 语句调用了这个函数。

对于for循环中执行的  funcs.push(function() { console.log(i) }) 实际上是funcs这个数组被push了10个匿名函数,其次,每个匿名函数在执行时都会打印已经被累加的变量i,而这个被打印出来的i值不是0~9,而是10,因为只有等for循环结束之后(此时i已经为10)才会去调用匿名函数。这里的 i 由于用var声明,所以是一个全局变量,最终循环结束, i 保存在内存中不会马上销毁,所以你在for循环结束的时候输出 i 可以看到结果为10。关于闭包问题请参考 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

for循环结束后,调用数组的 forEach 方法对数组进行相关处理,关于forEach详细介绍请参考 https://www.runoob.com/jsref/jsref-foreach.html

forEach()可以传入一个匿名函数作为参数,而该匿名函数有含有三个参数,其依次代表数组遍历时的当前元素item,数组遍历时的当前元素的索引index,以及正在遍历的数组array。有了这三个参数,可以方便我们做很多事情。其中第一个参数(数组遍历时的当前元素item是必需的,其他两个可选)。

那么对于 function(func) { func() } 这里的 func 其实就是数组funcs里面的元素,也就是匿名函数,然后再 func()执行匿名函数,从而输出十个10。

但是如果我们想输出 0~9 该如何做呢?有两种解决方法:
 
方法一:ES5的知识,我们可以利用 “立即调用函数” 解决这个问题
var funcs = []
    for (var i = 0; i < 10; i++) {
        funcs.push(
          (function(value) {
            return function() {
                console.log(value)
            }
        })(i)
      )
    }
    funcs.forEach(function(func) {
        func()
    })
 
 

方法二:通过ES6来解决

const funcs = []
    for (let i = 0; i < 10; i++) {
        funcs.push(function() {
            console.log(i)
        })
    }
    funcs.forEach(func => func())

 以上就是对本道题的理解。

posted @ 2020-05-12 11:54  BAHG  阅读(294)  评论(0编辑  收藏  举报