最近在写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]();
复制代码

我们可以看到,babelfor循环内的代码单独提取出来了,我们知道闭包可以捕获父级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直接在编译期就做了检查。

总结

letconst在编译后还是以var来声明变量,不同的地方在于,使用letconst声明的变量,如果在上下文环境中存在相同变量名的var,那么会自动将let声明的变量名改成其他名字,简单说就是对变量名在编译期进行重命名。而正是因为这样的重命名的改动,由此引出了很多ES6对于let的其他一些特性,比如:块级作用域暂时性死区等等。

注意:重命名不是let实现的全部

JavaScript:剖析ES6(1)--let和const相关推荐

  1. javascript的ES6学习总结(第三部分)

    1.ES6中的面向对象的类 1.1.定义类 在ES5中,我们写一个类,通常是这么写的 function Person(name,age){this.name = name;this.age = age ...

  2. [OHIF-Viewers]医疗数字阅片-医学影像-es6解构赋值-const{}=-let{}=

    [OHIF-Viewers]医疗数字阅片-医学影像-es6解构赋值-const{}=-let{}= 解构赋值语法是一种 Javascript 表达式.通过解构赋值, 可以将属性/值从对象/数组中取出, ...

  3. JavaScript (11) ES6语法

    1. ES6 语法 ECMAScript 6 是继ECMAScript 5 之后发布的JavaScript 语言的新一代标准,加入了很多新的特性和语法,该标准于2015年6月17日发布了正式版本,并被 ...

  4. 56 道高频 JavaScript 与 ES6+ 的面试题及答案

    前端硬核面试专题 前言 本文讲解 56 道 JavaScript 和 ES6+ 面试题的内容. 复习前端面试的知识,是为了巩固前端的基础知识,最重要的还是平时的积累! 注意:文章的题与题之间用下划线分 ...

  5. 带你一文读懂Javascript中ES6的Symbol

    带你一文读懂Javascript中ES6的Symbol 前言 基础类型 Symbol Symbol.for 与 Symbol.keyFor Symbol.iterator Symbol.search ...

  6. 2021前端JavaScript、ES6面试题归纳

    JS.ES6篇 es6的新特性 const let 模板字符串 箭头函数 函数的参数默认值 对象和数组解构 for...of 和 for...in(for in更适合遍历对象,for of更适合遍历数 ...

  7. 【ES6】 let与const详解

    [ES6] let与const详解 ES6,全称为ECMAScript6.ES6与js的关系是:前者是后者的规格,后者是前者的实现.换句话说,ES是js的国际化版本,js是ES的子集. 1. let ...

  8. ES6中使用let, const声明的变量, 在window对象下是获取不到的

    ES6中使用let, const声明的变量, 在window对象下是获取不到的 今天在写demo的时候发现, 使用let或者const声明的变量, 在window对象下使用this来获取发现获取不到 ...

  9. var和let和const_用故事讲解JavaScript的var,let和const变量

    var和let和const by Prarthana S. Sannamani 通过Prarthana S.Sannamani 用故事讲解JavaScript的var,let和const变量 (Jav ...

  10. es6(let与const命令)

    es6(let与const命令) 理论区别 var let const 在函数作用域内或者全局有效,没有块级作用域 只在let命令所在的代码块内有效 只在声明所在的块级作用域内有效 能重复声明 不能重 ...

最新文章

  1. Ruby中的设计模式
  2. js正则贪婪模式_JavaScript正则表达式迷你书之贪婪模式-学习笔记
  3. Android之如何解决刚下载的Android studio(包括上面的菜单栏)乱码问题
  4. c 语言 while break,26 C 语言中的break和continue - C 语言基础教程
  5. 快递下单后取消订单_网约车定位地点不动,男子别的平台下单,没取消订单要付6.6元...
  6. RTMP播放器开发填坑之道
  7. java8 两个list合并_深入介绍和使用 Java 8 的 Collector 接口和 Collectors 工具类
  8. [UE4]增加机器人
  9. 华为荣耀9x怎么解账户锁_跟华为毫无关系的荣耀为何不值得买?
  10. 【BZOJ 4011】[HNOI2015]落忆枫音
  11. 2的负x次幂图像_函数Y等于2的X次方图像怎么画?求过程
  12. c语言单片机程序段,51单片机C语言编程基础及实例
  13. dvd光驱在计算机内怎么找不到,为什么在我的电脑中找不到光驱了?
  14. 解决 Macbook 连接蓝牙鼠标卡顿、飘的现象
  15. STM32标准库工程中移植TencentOS-tiny
  16. 任天堂3D掌上游戏机3DS正式发布
  17. HTML 6种空格nbsp;ensp;emsp;thinsp;zwnj;zwj;空白空格的区别
  18. 倍福--步进电机的控制
  19. java项目常用的工具类
  20. VMware虚拟机ping不通主机,Destination Host Unreachable

热门文章

  1. 【三维路径规划】基于matlab人工势场算法无人机三维路径规划【含Matlab源码 168期】
  2. 烟台职业学院计算机,烟台职业学院首届计算机应用技能决赛落幕
  3. torch.optim.lr_scheduler.MultiStepLR()用法研究 台阶/阶梯学习率
  4. karma看fits文件软件操作汇总【第三个维度的变化】【查看某个范围的RMS值】
  5. rabbitmq direct 多个消费者_rabbitMQ消息队列入门介绍
  6. 自动刷新网页脚本_抢不到票?你离idol只差一个大麦抢票脚本。
  7. python一个类有几个实例对象_Python用一个类实例来解开一个对象
  8. php里= 啥意思,PHP natcasesort() 函数 | 菜鸟教程
  9. java map sort_Map 按值排序 (Map sort by value) – Java | 学步园
  10. linux RAID10测试