深入理解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 相关文章推荐
利用jQuery 实现GridView异步排序、分页的代码
Feb 06 Javascript
jquery DOM操作 基于命令改变页面
May 06 Javascript
javascript 通用简单的table选项卡实现
May 07 Javascript
js实现的点击数量加一可操作数据库
May 09 Javascript
基于豆瓣API+Angular开发的web App
Jan 02 Javascript
js实现可兼容IE、FF、Chrome、Opera及Safari的音乐播放器
Feb 11 Javascript
JS获取当前使用的浏览器名字以及版本号实现方法
Aug 19 Javascript
浅谈vue-lazyload实现的详细过程
Aug 22 Javascript
薪资那么高的Web前端必看书单
Oct 13 Javascript
如何将百度地图包装成Vue的组件的方法步骤
Feb 12 Javascript
vue等两个接口都返回结果再执行下一步的实例
Sep 08 Javascript
解决vue初始化项目一直停在downloading template的问题
Nov 09 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在XP下IIS和Apache2服务器上的安装
2006/09/05 PHP
浅析PHP递归函数返回值使用方法
2013/02/18 PHP
PHP数组相加操作及与array_merge的区别浅析
2016/11/26 PHP
PHP基于DOM创建xml文档的方法示例
2017/02/08 PHP
非常不错的功能强大代码简单的管理菜单美化版
2008/07/09 Javascript
详细讲解JS节点知识
2010/01/31 Javascript
javascript 基础篇1 什么是js 建立第一个js程序
2012/03/14 Javascript
js日期相关函数总结分享
2013/10/15 Javascript
jQuery.holdReady()方法用法实例
2014/12/27 Javascript
jQuery基于扩展简单实现倒计时功能的方法
2016/05/14 Javascript
web打印小结
2017/01/11 Javascript
JS中跳出循环的示例代码
2017/09/14 Javascript
微信小程序异步API为Promise简化异步编程的操作方法
2018/08/14 Javascript
Vue实现将数据库中带html标签的内容输出(原始HTML(Raw HTML))
2019/10/28 Javascript
原生js实现的观察者和订阅者模式简单示例
2020/04/18 Javascript
vue-router定义元信息meta操作
2020/12/07 Vue.js
python双向链表实现实例代码
2013/11/21 Python
python实现挑选出来100以内的质数
2015/03/24 Python
Python使用Supervisor来管理进程的方法
2015/05/28 Python
python实现爬虫下载美女图片
2015/07/14 Python
Python代码缩进和测试模块示例详解
2018/05/07 Python
对python打乱数据集中X,y标签对的方法详解
2018/12/14 Python
python与字符编码问题
2019/05/24 Python
Python 异常的捕获、异常的传递与主动抛出异常操作示例
2019/09/23 Python
Django admin禁用编辑链接和添加删除操作详解
2019/11/15 Python
tensorflow 初始化未初始化的变量实例
2020/02/06 Python
详解pandas中利用DataFrame对象的.loc[]、.iloc[]方法抽取数据
2020/12/13 Python
python爬虫线程池案例详解(梨视频短视频爬取)
2021/02/20 Python
使用HTML5 Canvas绘制圆角矩形及相关的一些应用举例
2016/03/22 HTML / CSS
欧洲最大的婴幼儿服装及内衣公司:Petit Bateau(小帆船)
2016/08/16 全球购物
static全局变量与普通的全局变量有什么区别
2014/05/27 面试题
医学类个人求职信范文
2014/02/05 职场文书
纪律教育学习月活动总结
2014/08/27 职场文书
餐厅保洁员岗位职责
2015/04/10 职场文书
SpringBoot+Vue+JWT的前后端分离登录认证详细步骤
2021/09/25 Java/Android
使用Django框架创建项目
2022/06/10 Python