js作用域链和闭包的理解
2017-04-19 11:31
363 查看
最近在做一个面试题时,无意中看到了一个闭包的题目,题目很简单,就是一个ul标签下面有多个li,给每个li添加点击事件,要求点击每个li弹出该li是第几个li。作为一个在前端面试中身经百战(lv zhan lv bai)的coder(lowser)来说,我当然知道要使用闭包来解决这个问题,具体代码如下:
或者使用let来声明循环变量,或者在循环类先用一个函数来先返回当前序号,然后在弹出,等等等等等方法都可以解决上述问题。
可是说上述类型的问题 ,遇到过不下于五六次了,虽然每次都能解决此类问题,但是心里一直有个结,就是老是感觉自己对这类问题的原因,有种一知半解的嫌疑,于是今天打算彻底fire掉它。那么问题来了:
出现这种情况的原因是,js语法不存在块级作用域,且存在着变量提升的机制。上述代码可以翻译成:
很明显了,js中var scope=’local’的声明和赋值,会被拆分为var scope;scope=‘local’;且声明会提升到当前作用域的最前面。
何为作用域?通常来说一段程序代码中使用的变量和函数并不总是可用的,限定其可用性的范围即作用域,作用域的使用提高了程序逻辑的局部性,增强程序的可靠性,减少名字冲突。
何为作用域链?当一个函数作用域里面又声明一个函数时,子函数就会继承父函数的作用域,父函数又会继承父父函数的作用域,….一级一级的,直到最顶层的作用域,这就形成了一个作用域链。函数的作用域链是在函数的创建的时候创建。
这是一个错误写法,结果是,不管点击那个li,弹出的都是li.length。通过以上对作用域链的理解,可以得知:
上述代码在页面加载完成后就会执行,for循环执行完成后,i的值变为li.length,当执行点击事件时,后面的匿名函数就是一个闭包,闭包i变量不会被销毁,所以每次都弹出li.length,没 毛病。
回到开头,如果for循环后紧跟使用一个自执行函数,又形成了一个闭包,使用num值保存每次循环的i值,这样就不会有问题了。
问题解决,
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值,这样就不会有问题了。
问题解决,
相关文章推荐
- 深入理解javascript原型和闭包(14)——从【自由变量】到【作用域链】
- js 作用域链&内存回收&变量&闭包
- 深入理解javascript原型和闭包(14)——从【自由变量】到【作用域链】
- 深入理解javascript原型和闭包(14)——从【自由变量】到【作用域链】
- JS作用域、作用域链与闭包详解
- JS函数作用域及作用域链理解
- JS 之作用域链和闭包
- 深入理解javascript原型和闭包——从【自由变量】到【作用域链】
- 深入理解javascript原型和闭包(14)——从【自由变量】到【作用域链】
- 深入理解javascript原型和闭包(14)——从【自由变量】到【作用域链】
- 一道题目理解js中变量在作用域链与原型链中的查找顺序
- 深入理解javascript原型和闭包(14)——从【自由变量】到【作用域链】
- 关于JS变量的作用域,作用域链与闭包
- 深入理解javascript原型和闭包(14)——从【自由变量】到【作用域链】
- js深入理解之作用域链
- js 作用域链&内存回收&变量&闭包
- 深入理解javascript原型和闭包系列 深入理解javascript原型和闭包(14)——从【自由变量】到【作用域链】
- JS闭包作用及理解
- 深入理解javascript原型和闭包(14)——从【自由变量】到【作用域链】
- 通过作用域链去理解闭包