深入理解ES6中let和闭包


Posted in Javascript onFebruary 22, 2018

本文介绍了深入理解ES6中let和闭包,分享给大家,具体如下:

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

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]());//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]());//3

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

let arr=[];
for(let i=0;i<10;i++){
  let k=i;
  arr[k]=function(){
    return k;
  }
}
console.log(arr[3]());//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 的。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js实现权限树的更新权限时的全选全消功能
Feb 17 Javascript
取得窗口大小 兼容所有浏览器的js代码
Aug 09 Javascript
JavaScript打字小游戏代码
Dec 26 Javascript
javascript面向对象入门基础详细介绍
Sep 05 Javascript
解决js正则匹配换行问题实现代码
Dec 10 Javascript
js获取当前日期代码适用于网页头部
Jun 27 Javascript
js opener的使用详解
Jan 11 Javascript
jQuery学习笔记之2个小技巧
Jan 19 Javascript
基于JavaScript如何实现私有成员的语法特征及私有成员的实现方式
Oct 28 Javascript
基于Jquery实现万圣节快乐特效
Nov 01 Javascript
使用Sticky组件实现带sticky效果的tab导航和滚动导航的方法
Mar 22 Javascript
实例详解Node.js 函数
Jun 10 Javascript
vue+iview+less+echarts实战项目总结
Feb 22 #Javascript
在vscode中统一vue编码风格的方法
Feb 22 #Javascript
vue webpack打包优化操作技巧
Feb 22 #Javascript
vue和react等项目中更简单的实现展开收起更多等效果示例
Feb 22 #Javascript
Vue 2.5.2下axios + express 本地请求404的解决方法
Feb 21 #Javascript
把vue-router和express项目部署到服务器的方法
Feb 21 #Javascript
浅谈在vue中用webpack打包之后运行文件的问题以及相关配置方法
Feb 21 #Javascript
You might like
php检测用户是否用手机(Mobile)访问网站的类
2014/01/09 PHP
PHP连接sql server 2005环境配置及问题解决
2014/08/08 PHP
PHP中执行cmd命令的方法
2014/10/11 PHP
WordPress中查询文章的循环Loop结构及用法分析
2015/12/17 PHP
php 微信公众平台开发模式实现多客服的实例代码
2016/11/07 PHP
PHP 表单提交及处理表单数据详解及实例
2016/12/27 PHP
php输出文字乱码的解决方法
2019/10/04 PHP
利用百度地图JSAPI生成h7n9禽流感分布图实现代码
2013/04/15 Javascript
Javascript delete 引用类型对象
2013/11/01 Javascript
JS 在指定数组中随机取出N个不重复的数据
2014/06/10 Javascript
javascript实现十六进制颜色值(HEX)和RGB格式相互转换
2014/06/20 Javascript
微信公众号 摇一摇周边功能开发
2016/12/08 Javascript
jQuery条件分页 代替离线查询(附代码)
2017/08/17 jQuery
使用vue制作FullPage页面滚动效果
2017/08/21 Javascript
React-Native使用Mobx实现购物车功能
2017/09/14 Javascript
Vue-Quill-Editor富文本编辑器的使用教程
2018/09/21 Javascript
Egg.js 中 AJax 上传文件获取参数的方法
2018/10/10 Javascript
javascript异步编程的六种方式总结
2019/05/17 Javascript
layui固定下拉框的显示条数(有滚动条)的方法
2019/09/10 Javascript
微信小程序动态添加和删除组件的现实
2020/02/28 Javascript
[01:00:17]DOTA2-DPC中国联赛 正赛 SAG vs Dynasty BO3 第二场 1月25日
2021/03/11 DOTA
如何用itertools解决无序排列组合的问题
2017/05/18 Python
python正则表达式及使用正则表达式的例子
2018/01/22 Python
python自动化实现登录获取图片验证码功能
2019/11/20 Python
恶意软件的定义
2014/11/12 面试题
年度考核自我鉴定
2013/11/09 职场文书
英文请假条
2014/04/11 职场文书
中学生社会实践活动总结
2014/07/03 职场文书
2014和解协议书范文
2014/09/15 职场文书
高校自主招生教师推荐信
2015/03/23 职场文书
车间主任岗位职责范本
2015/04/08 职场文书
新闻简讯格式及范文
2015/07/22 职场文书
社区志愿服务活动感想
2015/08/07 职场文书
机关干部纪律作风整顿心得体会
2016/01/23 职场文书
《珍珠鸟》教学反思
2016/02/16 职场文书
2019年圣诞节祝福语集锦
2019/12/25 职场文书