JavaScript:谈谈let和const
最近接触到ES6的一些相关新特性,想借let和const两个命令谈谈JavaScript在变量方面的改进。
由于let和const有很多相似之处,我们就先说一说let吧。
1. let添加了块级作用域
我们知道,JavaScript是没有块级作用域的,如果在块内使用var声明一个变量,它在代码块外面仍旧是可见的:
if (true) {
var foo = 3;
}
console.log(foo); //
for (var i = 0; i < 9; i++) {
var j = i;
}
console.log(i); //
console.log(j); // 8
可以看到,在上面代码中,我们虽然是在块内声明的变量,但代码块执行完毕后,依然可以访问到相应的变量,说明JavaScript中没有块级作用域的。
而ES6规范给开发者带来了块级作用域,如果把var换成let命令,我们就可以获得一个块级变量:
if (true) {
let foo = 3;
}
console.log(foo); // Uncaught ReferenceError
for (let i = 0; i < 9; i++) {
let j = i;
}
console.log(i); // Uncaught ReferenceError
console.log(j); // Uncaught ReferenceError
从上面代码可以看出,块内声明的变量,块外是不可见的,如果试图引用一个块内用let声明的变量,就会引发一个异常。
2. let约束了变量提升
在JavaScript中,变量提升是很常见的,例如下面这段代码:
function hoistVariable() {
console.log('foo:', foo); // foo: undefined
var foo = 3;
}
hoistVariable();
在代码正式执行之前,编译器将会对代码进行预编译分析阶段,在这个阶段,当前作用域中的变量和函数,将被提升到作用域的顶部。(注:目前的JavaScript引擎大都对源代码进行了编译处理,并且预编译和提升是抽象出来的概念。)
经过预编译之后的代码逻辑如下所示:
function hoistVariable() {
var foo;
console.log('foo:', foo); // foo: undefined
foo = 3;
}
hoistVariable();
ES6中的let命令规范了变量的声明,约束了变量提升,也就是说,我们必须先声明,然后才可以使用,下面者段代码将会报错:
function nonHoistingFunc() {
console.log('foo:', foo); // Uncaught ReferenceError
let foo = 3;
}
nonHoistingFunc();
正确的使用方式是,永远将变量声明置于当前作用域顶部:
function nonHoistingFunc() {
let foo = 3;
console.log('foo:', foo); //
}
nonHoistingFunc();
需要注意的是,不管是var还是let,预编译过程中,都发生了变量提升,但与var不同的是,ES6对let进行了约束,其规定,在真正的词法变量声明之前,以任何方式访问let变量都是不允许的,所以从开发人员角度来看,let禁止了变量提升这一行为。
关于这一点,大家可以参考ES6规范中“let和const变量的声明”。
3. let有暂时性死区
只要在块内存在let命令,那么这个变量就绑定到了当前块作用域,不再受外部变量的影响,下面代码将会引发一个错误:
var foo = 3;
if (true) {
foo = 5; // Uncaught ReferenceError
let foo;
}
ES6规定如果块内存在let命令,那么这个块就会成为一个封闭的作用域,并要求let变量先声明才能使用,如果在声明之前就开始使用,它并不会引用外部的变量。
如果把这里的let替换成var,由于不会形成块级作用域,变量的声明其实是与第一行重复了,相当于下面这段代码:
var foo;
foo= 3;
if (true) {
foo = 5;
}
4. let禁止重复声明变量
如上面所述,使用var可以重复声明变量,但let不允许在相同作用域内重复声明同一个变量,下面的代码会引发错误:
// SyntaxError
function func() {
let foo = 3;
var foo = 5;
} // SyntaxError
function func() {
let foo = 3;
let foo = 5;
} // SyntaxError
function func(arg) {
let arg;
}
5. let不会成为全局对象的属性
我们在全局范围内使用var声明一个变量时,这个变量会自动成为全局对象的属性(在浏览器和Node.js环境下,这个全局对象分别是window和global),但let是独立存在的变量,不会成为全局对象的属性:
var a = 3;
console.log(window.a); // let b = 5;
console.log(window.b); // undefined
6. 最后:const命令
以上let所介绍的规则均适用于const命令,不同的是,const声明的变量不能重新赋值,也是由于这个规则,const变量声明时必须初始化,不能留到以后赋值,所以下面的代码是不合法的:
const a = 3; a = 5; // Uncaught TypeError: Assignment to constant variable const b; // Uncaught SyntaxError: Missing initializer in const declaration
以上就是let和const的内容,可以看出,let和const大大改进了ES5的变量机制,使得JS更严谨和规范,随着ES6支持程度的提高,我们应该开始习惯let和const的使用了。
参考资料:
http://es6.ruanyifeng.com/#docs/let
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
JavaScript:谈谈let和const的更多相关文章
- JavaScript系列文章:谈谈let和const
JavaScript系列文章:谈谈let和const 最近接触到ES6的一些相关新特性,想借let和const两个命令谈谈JavaScript在变量方面的改进. 由于let和const有很多相似之 ...
- JavaScript ES6 let、const
在ES6中,增加了2个声明变量的关键字:let 和 const.在这里将详细介绍let与var的区别.Babel对let的处理以及const的简单使用. 1. let 在ES6规范中增加了 let 关 ...
- javascript中var let const三种变量声明方式
javascript中var let const三种变量声明方式 1.var ①var表示声明了一个变量,并且可以同时初始化该变量. ②使用var语句声明的变量的作用域是当前执行位置的上下文:一个函 ...
- 谈谈let与const
let 命令 let命令用于声明变量,但是与传统var命令的不同之处在于拥有以下特性: 使用let命令声明的变量只在let命令所在的代码块内有效(我将之称为变量绑定): 不存在变量提升: 存在暂时性死 ...
- JavaScript中的var,const,let区别与用法(浅谈)
let 和 const是(ES6) 新增加了两个重要的 JavaScript 关键字. 1.var全局变量 //全局变量在 JavaScript 程序的任何地方都可以访问 //定义的变量可以修改,如果 ...
- <JavaScript>谈谈javascript语法里一些难点问题(一)
1) 引子 前不久我建立的技术群里一位MM问了一个这样的问题,她贴出的代码如下所示: var a = 1; function hehe() { window.alert(a); var a = ...
- <javaScript>谈谈JavaScript中的变量、指针和引用
1.变量我们可能产生这样一个疑问:编程语言中的变量到底是什么意思呢?事实上,当我们定义了一个变量a时,就是在存储器中指定了一组存储单元,并将这组存储单元命名为a.变量a的值实际上描述的是这组存储单元中 ...
- JavaScript Let 和 Const
来源:菜鸟教程:https://www.runoob.com/js/js-let-const.html JavaScript let 和 const ECMAScript 2015(ECMAScrip ...
- JavaScript自学笔记(1)---表单验证,let和const,JSON文件
今天开个JS自学笔记,本身JS的语法很简单,如果学过Java或者C系的都很容易,就不讨论了.主要是讨论实际应用的问题. 1.表单验证: a.html自动验证: HTML 表单验证可以通过浏览器来自动完 ...
随机推荐
- 调用链系列三、基于zipkin调用链封装starter实现springmvc、dubbo、restTemplate等实现全链路跟踪
一.实现思路 1.过滤器实现思路 所有调用链数据都通过过滤器实现埋点并收集.同一条链共享一个traceId.每个节点有唯一的spanId. 2.共享传递方式 1.rpc调用:通过隐式传参.dubbo有 ...
- concurrent.futures- 启动并行任务
python因为其全局解释器锁GIL而无法通过线程实现真正的平行计算.这个论断我们不展开,但是有个概念我们要说明,IO密集型 vs. 计算密集型. IO密集型:读取文件,读取网络套接字频繁. 计算密集 ...
- 利用excel办公软件快速拼凑sql语句
日常工作中经常会收到excel整理好的部门或者人员等数据信息并需要批量更新或者插入到数据库中,常用的办法有导入.脚本拼凑执行等,今天我介绍直接使用excel快速拼凑sql语句的方法 1.update批 ...
- 解执行maven项目出现 SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder”. error
最近再弄maven项目,运行起来没有问题,但是Console控制台会报错,比如说如下的问题异常提示: 由此我们可以看出,报出错误的地方主要是slf4j的jar包,而故障码中“Failed to loa ...
- [学习笔记]JS 数组Array push相关问题
前言: 今天用写了一个二维数组,都赋值为零,然后更新其中一个值,结果和预期是不一样,会整列的相同位置都是同一个值. 1.用Chrome的控制台样例如下: arrs[2][2] =1的赋值,竟然是三个数 ...
- 转:Session,Token相关区别
参考地址:https://www.cnblogs.com/xiaozhang2014/p/7750200.html 1. 为什么要有session的出现?答:是由于网络中http协议造成的,因为htt ...
- js闭包实例汇总
本文是通过实例来帮助大家深刻理解js闭包,是篇非常不错的文章,这里推荐给大家,有需要的小伙伴可以参考下 Js闭包 闭包前要了解的知识 1. 函数作用域 (1).Js语言特殊之处在于函数内部可以直接读取 ...
- passive 的事件监听器(转载)
passive 的事件监听器 很久以前,addEventListener() 的参数约定是这样的: addEventListener(type, listener, useCapture) 后来,最后 ...
- 2017-2018-2 20155309南皓芯 Exp6 信息搜集与漏洞扫描
实践内容 1.各种搜索技巧的应用 2.DNS IP注册信息的查询 3.基本的扫描技术:主机发现.端口扫描.OS及服务版本探测.具体服务的查点 4.漏洞扫描:会扫,会看报告,会查漏洞说明,会修补漏洞 基 ...
- oracle分区表彻底删除的办法,处理删不掉的不规则表名
Oracle分区表彻底删除的办法当对一个不再使用的分区表进行drop后,查询user_tab_partitions视图发现出现如下不规则的分区表表名:SQL> select distinct t ...