js作用域链和闭包的理解

最近在做一个面试题时,无意中看到了一个闭包的题目,题目很简单,就是一个ul标签下面有多个li,给每个li添加点击事件,要求点击每个li弹出该li是第几个li。作为一个在前端面试中身经百战(lv zhan lv bai)的coder(lowser)来说,我当然知道要使用闭包来解决这个问题,具体代码如下:

  var li=document.getElementsByClassName('liClass');
  for(var i=0;i<li.length;i++)
    {
        (function(num){
            li[num].onclick=function(){
            alert(num);}
        })(i)
    }

或者使用let来声明循环变量,或者在循环类先用一个函数来先返回当前序号,然后在弹出,等等等等等方法都可以解决上述问题。
可是说上述类型的问题 ,遇到过不下于五六次了,虽然每次都能解决此类问题,但是心里一直有个结,就是老是感觉自己对这类问题的原因,有种一知半解的嫌疑,于是今天打算彻底fire掉它。那么问题来了:

什么是js的作用域链?

先展示一段代码:

var scope="global";  
function t(){  
    console.log(scope);   //undefined
    var scope="local"  
    console.log(scope);  //local
}  
t(); 

出现这种情况的原因是,js语法不存在块级作用域,且存在着变量提升的机制。上述代码可以翻译成:

   var scope="global";  
function t(){  
    var scope;  
    console.log(scope);   //undefined
    scope="local"  ;
    console.log(scope);  //local
}  
t();

很明显了,js中var scope=’local’的声明和赋值,会被拆分为var scope;scope=‘local’;且声明会提升到当前作用域的最前面。

何为作用域?通常来说一段程序代码中使用的变量和函数并不总是可用的,限定其可用性的范围即作用域,作用域的使用提高了程序逻辑的局部性,增强程序的可靠性,减少名字冲突。

何为作用域链?当一个函数作用域里面又声明一个函数时,子函数就会继承父函数的作用域,父函数又会继承父父函数的作用域,….一级一级的,直到最顶层的作用域,这就形成了一个作用域链。函数的作用域链是在函数的创建的时候创建。

什么是闭包?

回到最开始的那个题目,写一个错误的实现方法:

 var li=document.getElementsByClassName('liClass');
  for(var i=0;i<li.length;i++)
    {
        li[i].onclick=function(){
            alert(i);
        }
    }

这是一个错误写法,结果是,不管点击那个li,弹出的都是li.length。通过以上对作用域链的理解,可以得知:
上述代码在页面加载完成后就会执行,for循环执行完成后,i的值变为li.length,当执行点击事件时,后面的匿名函数就是一个闭包,闭包i变量不会被销毁,所以每次都弹出li.length,没 毛病。
回到开头,如果for循环后紧跟使用一个自执行函数,又形成了一个闭包,使用num值保存每次循环的i值,这样就不会有问题了。
问题解决,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值