js作用域链和闭包的理解

来源:互联网 发布:榕基软件股票行情 编辑:程序博客网 时间:2024/06/02 07:31

最近在做一个面试题时,无意中看到了一个闭包的题目,题目很简单,就是一个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 0