腾讯js面试题3

该题难度系数: ★★★

考查的技术点: 1). DOM事件处理  2). 闭包

题目如下:

  /*
   需求: 点击某个按钮, 提示"第n个"
   问题: 下面的实现代码是否正确, 如果不正确, 请正确实现
   */
  var btns = document.getElementsByTagName('button')
  for(var i=0,length=btns.length;i<length;i++) { 
    var btn = btns[i];
    btn.onclick = function () {
      alert('第'+(i+1)+'个');
    }
  }


单击每个按钮得到的运行结果均如图所示:


根据结果,这明显是错误的啊。

那为什么会这样子呢?这明显不是我们想要的结果啊。因为i是一个全局变量(函数级变量),而3个内部函数都指向了同一个i,且最后一次i的赋值是3,所以点击弹窗时就是用同一个变量的。

那么接下来,我们该如何修改这段代码呢?目前想到几种方法:

第一种,用let代替var;

就是在for循环体里,把var换成let即可,如下所示:

  var btns = document.getElementsByTagName('button')
  for(let i=0,length=btns.length;i<length;i++) {
    var btn = btns[i]
    btn.onclick = function () {
      alert('第'+(i+1)+'个')
    }
  }

此时的结果就是我们要的结果了:


那原理是什么呢?根据官方文档得知let就是声明一个块范围变量,即该变量的范围限于声明它的块中。就是let 允许把变量的作用域限制在块级域中,而var 申明变量要么是全局的,要么是函数级的,而无法是块级的,这就是let的精妙之处。i 变成块级域(也就是花括号中的块,每进入一次for的花括号就生成了一个块级域),所以3个内部函数指向了不同的i。


第二种,使用闭包。

那什么是闭包呢?一般两个条件,一是函数嵌套函数,二是函数可以访问另外一个函数的局部变量。简言之,有权访问另一个函数作用域内变量的函数都是闭包,这样就形成了一个闭包。

先来看个小案例:

  function fn1() {
    var a = 2
    function fn2 () {
      a++
      console.log(a)
    }
    return fn2
  }
  var f = fn1()
  f()
  f()
结果如下:


分析如下:


我们在浏览器debug调试一下这段代码,刚开始闭包里面a为2,closure就是闭包的意思。


这时候输出的是3了,


再接下来,就是输出4了


这说明了,闭包可以实现局部变量的累加。但是要注意一点,不必要的闭包只会徒增内存消耗。


好的,言归正传,我们再来看下这道题目,用闭包如何实现,代码如下所示:

    var btns = document.getElementsByTagName('button')
    for(var i=0,length=btns.length;i<length;i++) {
        (function (i) {
            var btn = btns[i]
            btn.onclick = function () {
            alert('第'+(i+1)+'个')
            }
        })(i)
    }
得到的是正确的结果:


原因是加了闭包之后,内存里面新增了3个不同的i,确切的说是4个,因为for里面也有一个i,3个内部函数指向了不同的i。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值