在开始本文之前我们先来看一段代码

for(var i=0;i<10;i++){
arr[i]=function(){
return i;
}
}
console.log(arr[3]());//10

显然这段代码输出10,并没有向我们期望的返回3,原因也很简单(js的变量提升)函数在调用时候访问的是一个全局作用域的i,此时for循环已经执行完毕,全局变量i=10;

在ES5标准中,我们要想返回期望的3,通常的做法也很简单,就是让数组中的每个函数有单独的作用域,那么我们只要构造一个立即执行函数即可(js中没有块级作用域,只区分函数作用域和全局作用域)就像下面这样:

var array=[];
for(var i=0;i<10;i++){
array[i]=(function(i){
return function(){
return i;
}
})(i);
}
console.log(array[3]());//

这样一来数组的每个函数就处于一个立即执行函数的函数作用域中,该立即执行函数传入i,其实for循环执行了如下代码:

    array[0]=(function(i){
return function(){
return i;
}
})(0);
array[1]=(function(i){
return function(){
return i;
}
})(1);
array[2]=(function(i){
return function(){
return i;
}
})(2);
……

  这样一来,数字组中每个函数对应一个单独的函数作用域(立即执行函数的)这里共创建了10个函数作用域,这些函数作用域里的i值就是执行时候传入的0……9,当执行

array[3]();时候函数访问的i值是其对应的立即执行函数作用域里的 i,而不是全局的i值,这样我们就得到了预期的效果。

说得到这里我们简单来说一下闭包,闭包可以理解为一个闭包就是一个没有释放资源的栈区,栈区内的变量处于激活状态。上面的例子中for循环在执行时系统分配内存,js执行线程创建执行栈区,执行时候检测到立即执行函数里的变量i被内部函数引用,所以该栈区在内存中没有被释放,函数(数组元素)被调用时候根据作用链首先访问到的是上一级作用域(立即执行函数)的变量。

  这里不再详细介绍闭包,如果想详细了解闭包请阅读《javascript高级程序设计》第7章

  前面提到js中并没有块级作用域,只区分全局作用域和函数作用域,在ES6中let实际是为js新增了块级作用域,例如下面代码不用创造函数作用域就可以让每个数组里的函数访问各自作用域里的值:

let arr=[];
for(let i=0;i<10;i++){
arr[i]=function(){
return i;
}
}
console.log(arr[3]());//

可以看到我们并没有像之前那样构造一个函数作用域就能实现我们期望的效果,引入块级作用域之后更方便我们书写和理解代码,上述代码中for循环之后的{}是块级作用域,每次循环时候每个返回的函数引用的是其对应块作用域的变量,稍微改一下代码看着形象些:

let arr=[];
for(let i=0;i<10;i++){
let k=i;
arr[k]=function(){
return k;
}
}
console.log(arr[3]());//

可见ES6引入块作用域之后我们构造闭包函数更方便了。

这里不多叙述let和const的相关内容,如果之前没接触ES6的小伙伴建议阅读阮一峰老师的《ES6标准入门》。

在这里再提一点,很多人看完概念之后,第一印象都是:“const 是表示不可变的值,而 let 则是用来替换原来的 var 的。”很多时候把let当做是var的替代品,凡是声明变量就用let,你很可能写出下面代码:

  // 定义常量
const REG_GET_INPUT = /^\d{1,3}$/; // 定义配置项
let config = {
isDev : false,
pubDir: './admin/'
} let path = require('path');
let HtmlWebpackPlugin = require('html-webpack-plugin');
let CleanWebpackPlugin = require('clean-webpack-plugin');

  const 的定义是不可重新赋值的值,与不可变的值(immutable value)不同;const 定义的 Object,在定义之后仍可以修改其属性。

所以其实他的使用场景很广,包括常量、配置项以及引用的组件、定义的 “大部分” 中间变量等,都应该以cosnt做定义。反之就 let 而言,他的使用场景应该是相对较少的,我们只会在 loop(for,while 循环)及少量必须重定义的变量上用到他。

猜想:就执行效率而言,const 由于不可以重新赋值的特性,所以可以做更多语法静态分析方面的优化,从而有更高的执行效率。

所以上面代码中,所有使用 let 的部分,其实都应该是用 const 的。

ES6中let和闭包的更多相关文章

  1. javascript中重要概念-闭包-深入理解

    在上次的分享中javascript--函数参数与闭包--详解,对闭包的解释不够深入.本人经过一段时间的学习,对闭包的概念又有了新的理解.于是便把学习的过程整理成文章,一是为了加深自己闭包的理解,二是给 ...

  2. ES6中export , export default , import模块系统总结

    最近在学习使用Webpack3的时候发现,它已经可以在不使用babel的情况下使用ES6的模块加载功能了. 说到ES6的模块加载功能,我们先复习一下CommonJS规范吧: 一  . CommonJS ...

  3. ES6中的类继承和ES5中的继承模式详解

    1.ES5中的继承模式 我们先看ES5中的继承. 既然要实现继承,首先我们得要有一个父类. Animal.prototype.eat = function(food) { console.log(th ...

  4. ES6中比较实用的几个特性

    1.Default Parameters(默认参数) in ES6 es6之前,定义默认参数的方法是在一个方法内部定义 var link = function (height, color, url) ...

  5. 大厂HR面试必备ES6中的深入浅出面试题知识点

    ESMAScript6简介,ES6是JavaScript语言的下一代标准,目的是让JavaScript语言可以写复杂的大型应用程序,成为企业级语言.那么ECMAScript和JavaScript的关系 ...

  6. 前端知识体系:JavaScript基础-原型和原型链-理解 es6 中class构造以及继承的底层实现原理

    理解 es6 中class构造以及继承的底层实现原理 原文链接:https://blog.csdn.net/qq_34149805/article/details/86105123 1.ES6 cla ...

  7. es6中let实例应用之一

    有如下情景 html部分: <button class="btn">按钮1</button> <button class="btn" ...

  8. ES6中的模板字符串和新XSS Payload

    ES6中的模板字符串和新XSS Payload 众所周知,在XSS的实战对抗中,由于防守方经常会采用各种各样严格的过滤手段来过滤输入,所以我们使用的XSS Payload也会根据实际情况作出各种各样的 ...

  9. ES5和ES6中的继承 图解

    Javascript中的继承一直是个比较麻烦的问题,prototype.constructor.__proto__在构造函数,实例和原型之间有的 复杂的关系,不仔细捋下很难记得牢固.ES6中又新增了c ...

随机推荐

  1. TI-RTOS 之 GPIO中断(按键)

    TI-RTOS 之 GPIO中断(按键) 前面已经用过LED, 定时器,这次来了解GPIO的中断是怎么用的,从CC1310+TI-RTOS的例程可以直接找到相应的例子程序,它的关键是在于要使能中断,也 ...

  2. UEP-标签

    这里的标签都是常用不好理解的: formatfunc="showFormatNumer" 显示数字在页面上 ockedcolumnnum="6" 几列是不动的 ...

  3. Java本地缓存解决方案其一(使用Google的CacheBuilder)

    前不久,业务实现上需要用到本地缓存来解决一些数据量相对较小但是频繁访问的数据,通过查找各种资料,找到了一种可以实现的方案--采用的是Google的CacheBuilder.下面是代码实现过程:1.首先 ...

  4. Sass嵌套

    Sass 中还提供了选择器嵌套功能,但这也并不意味着你在 Sass 中的嵌套是无节制的,因为你嵌套的层级越深,编译出来的 CSS 代码的选择器层级将越深,这往往是大家不愿意看到的一点. 选择器嵌套为样 ...

  5. OKMX6Q ffmpeg & ffserver

    通过ltib在根文件系统中增加mplayer和ffmpeg后,拟使用ffmpeg从摄像头(/dev/video0)采集视频. 刚开始使用了: ffmpeg -f video4linux2 -s 320 ...

  6. iOS的相对路径和绝对路径

    iOS程序有固定的文件访问限制,只能在自己的沙盒内. UIImage *img=[UIImage imageNamed:@"cellicon.png"]; 这段代码从相对路径加载了 ...

  7. 【开发技术】如何查看项目中struts的版本

    struts-configer.xml(struts1)或struts.xml(struts2)中 struts-2.0.dtd处表示版本号

  8. EditText之边框颜色

    EditText的自带属性里没有设置边框颜色的 有俩种方式可以达到效果 一种是网上比较推崇的用图作背景,另一种则是自绘 图作背景的: 首先重新定义一个style.在values文件夹下新建一个styl ...

  9. hibernate.dialect是干嘛用的?

    dialect[ˈdaɪəlekt]就是“方言”,因为hibernate是要把Java对象转换成关系数据库来描述的,而关系数据库虽然有一些统一的标准,如SQL-92等,但是实际上各数据库如Oracle ...

  10. 理解rem实现响应式布局原理及js动态计算rem

    前言 移动端布局中,童鞋们会使用到rem作为css单位进行不同手机屏幕大小上的适配.那么来讲讲rem在其中起的作用和如何动态设置rem的值. 1.什么是rem rem是相对于根元素(html标签)的字 ...