javascript 中的立即调用函数模式、闭包及es6中的块级作用域

先来看一个在牛客上看到的面试题:

这里一开始会以为是不就是隔1秒输出i的值吗,最后结果就是输出0~9 的十个数字呀,真的是太young了。

但是真是撸了一遍代码,控制台输出刺眼的10个10,what?

这个查了资料是说因为这个函数为每一个i都设置了一个计时器,那么就设置了10个计时器,但是它们被存放在队列中,for循环结束

后setTimeout()函数才得以执行,而这时i的值为10,于是就输出10个10,如果还是不太明显,再看以下例子--->

这段代码利用var在循环中创建了一个函数,然后在循环外调用函数, 得到的结果却不是0到9,输出的是10个10,这是因为每次

循环里的每次迭代同时共享着变量 i ,循环内部创建的函数全都保留着对相同变量的引用,循环结束变量i的值为10,所以每次调用console.log(i) 时输出的数字为10。

 

那么如何输出0到9呢,从以上两个例子去修改。方法有两种,第一种是使用闭包(有时会结合IIFE模式使用);第二种是使用

ES6的块级作用域,用let 声明变量。看看具体实现

 

这个是使用闭包实现输出0到10 十个数字, 闭包类似其他类C语言的类和块的概念类似,这里通过与理解调用函数模式结合,创建后立即调用,可以在外部访问到局部创建的函数域里的变量。

这里使用立即调用函数表达式,强制生成计数器变量的副本并储存为变量value,这个变量的值就是相应迭代创建的函数所使用

的值,因此调用每个函数都会像从0到9一样得到期望值。

 

块级作用域----用let关键字声明变量,相对于闭包操作简单一点:

这里仅仅是用let 关键字代替了 var 就得到想要的结果,输出0到10 每个数字, var 声明在函数中会有变量提升,let 声明则没有这个变量提升.

let 声明模仿IIFE模式,每次迭代循环都会创建一个新的变量,并以之前迭代中同名变量的值将其初始化。

同样也可以用const 声明实现类似的结果。

关于let声明和const声明可以多去看看es6的文档。不过这个闭包和立即调用模式还有变量提升真的是深坑,不多跳几次还是不会

长记性的。

-------------写这篇博文时太阳刚好西斜,晒到我半边身子,满满阳光的味道。怕什么坑太多,能填一个是一个。

 

展开阅读全文

没有更多推荐了,返回首页