JavaScript:剖析ES6(1)--let和const
最近在写GICXMLLayout
开源库的时候要支持JavaScript
,而在实现的过程中对于ES6
的实现原理也有了进一步的了解,因此写几篇博客,已做记录。
注意:
文中出现的结论,只能代表是在使用babel编译的情况下的结论
一、let
先从一个简单的例子开始。
例子1
let a = 1;
console.log(a);
复制代码
经过babel
编译后的代码如下:
var a = 1;
console.log(a);
复制代码
我们会发现,let
在这样的场景下,跟var
是没有区别的。
例子2
那如果是这样呢?
{let a = 1;console.log(a);
}
console.log(a);
复制代码
经过babel
编译后的代码如下:
{var _a = 1;console.log(_a);//2
}
console.log(a);// ReferenceError
复制代码
运行上面的代码,对于大括号外面的console.log(a);
会直接报ReferenceError
错误。之所以会出现这样的情况,是因为babel
在编译的时候将let a
编译成了var _a
,并且将同级作用域内的变量引用一并改为_a
,而作用域外的引用没有改变。
例子3 (变量提升)
这个例子是有关let
的变量提升
。
console.log(bar);
let bar = 2;
复制代码
经过babel
编译后的代码如下:
console.log(bar);
var bar = 2;
复制代码
从这里可以看出,let
声明的变量,其实还是存在变量提升
的问题的。并没有像ES6
规范中提到的那样let
可以阻止变量提升
。然而如果你使用如下代码就又不一样了。
console.log(bar);
{let bar = 2;
}
复制代码
经过babel
编译后的代码如下:
console.log(bar);// ReferenceError
{var _bar = 2;
}
复制代码
运行这样的代码你就会得到一个ReferenceError
的错误。看起来好像是阻止了变量提升
。但我们仔细分析下的话,这完全是因为let
在一个块级作用域内
定义了,而babel
在编译的时候只是将变量名称重命名了而已。
从上面的几个例子也进一步可以分析出,
let
的所谓块级作用域
,简单理解是在同一个作用域内引用的变量名称,在编译的时候被重命名了,而作用域外的变量名不会被重命名
,由此引出的结果是,由于变量名被重命名了,因此,对于作用域外的变量名就会报ReferenceError
的错误。这也就引出了let
的块级作用域
、暂时性死区
等一系列特性。
例子4(循环迭代)
这个例子是有关循环的例子。
var a = [];
for (let i = 0; i < 10; i++) {a[i] = function () {console.log(i);};
}
a[6](); // 6
复制代码
如果你把上面的代码中let
换成var
那么a[6]();
输出的将会是10
。之所以这样,我们分析下经过babel
编译后的代码:
var a = [];
var _loop = function (i) {a[i] = function () {console.log(i);};
};
for (var i = 0; i < 10; i++) {_loop(i);
}
a[6]();
复制代码
我们可以看到,babel
将for循环
内的代码单独提取出来了,我们知道闭包
可以捕获父级function
的变量,并且我们也知道对于number
这样的基本数据类型,JS
在传参的时候是直接拷贝的,而不是引用。因此对于_loop
这个方法,每次传过来的i
都会被拷贝一份,而闭包
捕获的变量仅仅是一个已经被拷贝的变量而已,也即是变量的地址已经改变,不是for
循环中i
的地址了。在没有let
的时候,要解决这样的问题,我们采用的方法往往也是使用闭包
(立即执行函数)来实现。
例子5
var tmp = 123;
if (true) {{tmp = 'abc'; }let tmp;
}复制代码
经过babel
编译后的代码如下:
var tmp = 123;
if (true) {{_tmp = 'abc';//ReferenceError}var _tmp;
}
复制代码
运行上面的例子你会得到一个ReferenceError
的错误。这个例子充分说明了let
关键字的块级作用域
的功能,只要是在同级作用域内,所有引用了相同变量名的地方都会被编译成新的变量名
。
我们可以得出一个结论。
let
的块级作用域的本质就是通过babel重命名变量
。
例子6
let a = 10;var a = 1;
复制代码
这样的代码,你连编译都无法编译,ES6规定在同级作用域内
不允许存在相同的变量名,因此babel
直接在编译期就报错了。
二、const
const
的原理跟let
其实差不多。但是多了一个不可重复赋值。
例子1
const PI = 3.1415;
PI = 10;
复制代码
经过babel
编译后的代码如下:
function _readOnlyError(name) { throw new Error("\"" + name + "\" is read-only"); }var PI = 3.1415;
PI = (_readOnlyError("PI"), 10);
复制代码
我们可以从编译后的代码中看到,当我们试图对一个const的变量赋值的时候,babel
直接将赋值代码替换成直接调用_readOnlyError
方法来抛出异常。
例子2
const
必须在声明变量的时候就赋值。如果我们不赋值呢?比如下面
const PI;
复制代码
你会发现,无法完成编译。babel
直接在编译期就做了检查。
总结
let
和const
在编译后还是以var
来声明变量,不同的地方在于,使用let
或const
声明的变量,如果在上下文环境中存在相同变量名的var
,那么会自动将let
声明的变量名改成其他名字,简单说就是对变量名在编译期进行重命名
。而正是因为这样的重命名
的改动,由此引出了很多ES6
对于let
的其他一些特性,比如:块级作用域
、暂时性死区
等等。
注意:重命名
不是let
实现的全部
JavaScript:剖析ES6(1)--let和const相关推荐
- javascript的ES6学习总结(第三部分)
1.ES6中的面向对象的类 1.1.定义类 在ES5中,我们写一个类,通常是这么写的 function Person(name,age){this.name = name;this.age = age ...
- [OHIF-Viewers]医疗数字阅片-医学影像-es6解构赋值-const{}=-let{}=
[OHIF-Viewers]医疗数字阅片-医学影像-es6解构赋值-const{}=-let{}= 解构赋值语法是一种 Javascript 表达式.通过解构赋值, 可以将属性/值从对象/数组中取出, ...
- JavaScript (11) ES6语法
1. ES6 语法 ECMAScript 6 是继ECMAScript 5 之后发布的JavaScript 语言的新一代标准,加入了很多新的特性和语法,该标准于2015年6月17日发布了正式版本,并被 ...
- 56 道高频 JavaScript 与 ES6+ 的面试题及答案
前端硬核面试专题 前言 本文讲解 56 道 JavaScript 和 ES6+ 面试题的内容. 复习前端面试的知识,是为了巩固前端的基础知识,最重要的还是平时的积累! 注意:文章的题与题之间用下划线分 ...
- 带你一文读懂Javascript中ES6的Symbol
带你一文读懂Javascript中ES6的Symbol 前言 基础类型 Symbol Symbol.for 与 Symbol.keyFor Symbol.iterator Symbol.search ...
- 2021前端JavaScript、ES6面试题归纳
JS.ES6篇 es6的新特性 const let 模板字符串 箭头函数 函数的参数默认值 对象和数组解构 for...of 和 for...in(for in更适合遍历对象,for of更适合遍历数 ...
- 【ES6】 let与const详解
[ES6] let与const详解 ES6,全称为ECMAScript6.ES6与js的关系是:前者是后者的规格,后者是前者的实现.换句话说,ES是js的国际化版本,js是ES的子集. 1. let ...
- ES6中使用let, const声明的变量, 在window对象下是获取不到的
ES6中使用let, const声明的变量, 在window对象下是获取不到的 今天在写demo的时候发现, 使用let或者const声明的变量, 在window对象下使用this来获取发现获取不到 ...
- var和let和const_用故事讲解JavaScript的var,let和const变量
var和let和const by Prarthana S. Sannamani 通过Prarthana S.Sannamani 用故事讲解JavaScript的var,let和const变量 (Jav ...
- es6(let与const命令)
es6(let与const命令) 理论区别 var let const 在函数作用域内或者全局有效,没有块级作用域 只在let命令所在的代码块内有效 只在声明所在的块级作用域内有效 能重复声明 不能重 ...
最新文章
- Ruby中的设计模式
- js正则贪婪模式_JavaScript正则表达式迷你书之贪婪模式-学习笔记
- Android之如何解决刚下载的Android studio(包括上面的菜单栏)乱码问题
- c 语言 while break,26 C 语言中的break和continue - C 语言基础教程
- 快递下单后取消订单_网约车定位地点不动,男子别的平台下单,没取消订单要付6.6元...
- RTMP播放器开发填坑之道
- java8 两个list合并_深入介绍和使用 Java 8 的 Collector 接口和 Collectors 工具类
- [UE4]增加机器人
- 华为荣耀9x怎么解账户锁_跟华为毫无关系的荣耀为何不值得买?
- 【BZOJ 4011】[HNOI2015]落忆枫音
- 2的负x次幂图像_函数Y等于2的X次方图像怎么画?求过程
- c语言单片机程序段,51单片机C语言编程基础及实例
- dvd光驱在计算机内怎么找不到,为什么在我的电脑中找不到光驱了?
- 解决 Macbook 连接蓝牙鼠标卡顿、飘的现象
- STM32标准库工程中移植TencentOS-tiny
- 任天堂3D掌上游戏机3DS正式发布
- HTML 6种空格nbsp;ensp;emsp;thinsp;zwnj;zwj;空白空格的区别
- 倍福--步进电机的控制
- java项目常用的工具类
- VMware虚拟机ping不通主机,Destination Host Unreachable
热门文章
- 【三维路径规划】基于matlab人工势场算法无人机三维路径规划【含Matlab源码 168期】
- 烟台职业学院计算机,烟台职业学院首届计算机应用技能决赛落幕
- torch.optim.lr_scheduler.MultiStepLR()用法研究 台阶/阶梯学习率
- karma看fits文件软件操作汇总【第三个维度的变化】【查看某个范围的RMS值】
- rabbitmq direct 多个消费者_rabbitMQ消息队列入门介绍
- 自动刷新网页脚本_抢不到票?你离idol只差一个大麦抢票脚本。
- python一个类有几个实例对象_Python用一个类实例来解开一个对象
- php里= 啥意思,PHP natcasesort() 函数 | 菜鸟教程
- java map sort_Map 按值排序 (Map sort by value) – Java | 学步园
- linux RAID10测试