深入理解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 相关文章推荐
随机显示经典句子或诗歌的javascript脚本
Aug 04 Javascript
JavaScript中的闭包原理分析
Mar 08 Javascript
jQuery在IE下使用未闭合的xml代码创建元素时的Bug介绍
Jan 10 Javascript
document.forms[].submit()使用介绍
Feb 19 Javascript
JavaScript实现算术平方根算法-代码超简单
Sep 11 Javascript
Vue.js鼠标悬浮更换图片功能
May 17 Javascript
JavaScript正则表达式简单实用实例
Jun 23 Javascript
JavaScript基本语法_动力节点Java学院整理
Jun 26 Javascript
weex slider实现滑动底部导航功能
Aug 28 Javascript
jQuery Ajax实现Select多级关联动态绑定数据的实例代码
Oct 26 jQuery
详解微信UnionID作用
May 15 Javascript
AI小程序之语音听写来了,十分钟掌握百度大脑语音听写全攻略
Mar 13 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垃圾回收机制简单说明
2010/07/22 PHP
php设计模式 Factory(工厂模式)
2011/06/26 PHP
php目录遍历函数opendir用法实例
2014/11/20 PHP
简单介绍PHP的责任链编程模式
2015/08/11 PHP
php倒计时出现-0情况的解决方法
2016/07/28 PHP
yii2.0框架数据库操作简单示例【添加,修改,删除,查询,打印等】
2020/04/13 PHP
jQuery获得内容和属性示例代码
2014/01/16 Javascript
JS合并数组的几种方法及优劣比较
2014/09/19 Javascript
javascript定义变量时带var与不带var的区别分析
2015/01/12 Javascript
jquery实现简洁文件上传表单样式
2015/11/02 Javascript
轻松学习jQuery插件EasyUI EasyUI表单验证
2015/12/01 Javascript
javascript拖拽应用实例
2016/03/25 Javascript
javascript 广告移动特效的实现代码
2016/06/25 Javascript
Centos7 中安装 Node.js v4.4.4
2016/11/03 Javascript
探索Javascript中this的奥秘
2016/12/11 Javascript
JavaScript设置名字输入不合法的实现方法
2017/05/23 Javascript
jQuery简单实现对数组去重及排序操作实例
2017/10/31 jQuery
详解vue-cli 2.0配置文件(小结)
2019/01/14 Javascript
详解微信小程序开发用户授权登陆
2019/04/24 Javascript
ES6使用新特性Proxy实现的数据绑定功能实例
2020/05/11 Javascript
[00:10]DOTA2全国高校联赛 以DOTA2会友
2018/05/30 DOTA
Python写入数据到MP3文件中的方法
2015/07/10 Python
详解Python中映射类型(字典)操作符的概念和使用
2015/08/19 Python
Django日志模块logging的配置详解
2017/02/14 Python
Python set常用操作函数集锦
2017/11/15 Python
python简单实例训练(21~30)
2017/11/15 Python
uwsgi+nginx部署Django项目操作示例
2018/12/04 Python
Pycharm debug调试时带参数过程解析
2020/02/03 Python
python中的unittest框架实例详解
2021/02/05 Python
Python项目实战之使用Django框架实现支付宝付款功能
2021/02/23 Python
美国购买当代和现代家具网站:MODTEMPO
2018/07/20 全球购物
澳大利亚在线性感内衣商店:Fantasy Lingerie
2021/02/07 全球购物
竞争上岗演讲稿
2014/01/05 职场文书
幼儿教师寄语集锦
2014/04/03 职场文书
项目委托协议书(最新)
2014/09/13 职场文书
maven 解包依赖项中的文件的解决方法
2022/07/15 Java/Android