ECMAScript6 中的let和const
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言,如果你学习完了JavaScript的全部内容,那接下来你需要学习的肯定是ES6,在这其中有许多新型的语法和新增的扩展方法,接下来让我们来学习ES6的第一个知识点let和const命令
ES6当中新增了let和const命令来声明变量 接下来让我来康康这新增的两个命令有什么作用
let
以前我们声明变量的方式都是使用var
//这是用var声明变量
var a = 10
//这是用let声明变量
let b = 10
废话少说让我们直接看看它们有什么不同的地方
{
var a = 3
let b = 4
}
//在代码块之外使用变量
console.log(a) //3
console.log(b) //ReferenceError: a is not defined.
let声明的变量只在它所在的代码块中有效,在这里大括号代表的是一个区块 也是ES6新增的一个作用域 也就是说如果我们使用let声明变量在if语句的{}中或者for循环语句的{}中,变量就会存在于块级作用域中
让我们来看个例子:由于i是在for循环代码块中定义的 所以在外层console会报错 也就是说let是不存在变量提升的
for(let i = 0; i < 10; i++){
//某些代码
}
console.log(i) // ReferenceError: i is not defined
再看一个例子:这个例子可以说是let很经典的一个例子 刚开始学习let可能要理解很久这个例子
var a = [] //定义a是一个数组
for(var i = 0; i < 10; i++){
a[i] = function(){
console.log(i) //这个循环原本想达到的目的是取a数组的第n位里的console.log的i
}
}
a[6]() // 10 结果就是无论在[]中填多少结果都是10
其实不难理解这个例子 因为var定义变量是存在提升的 当循环开始的时候var i已经被提升到了全局,然后for循环内部是一个函数表达式,需要执行函数才会打印结果,当我们最后一步执行函数的时候 for循环早已完成 变量i也早已+到了10 所以最后打印结果i是10
如果是用let就不会存在这个问题
var a = []
for(let i = 0; i < 10; i++){
a[i] = function(){
console.log(i)
}
}
a[6]() // 6
因为i是let声明的 所以该变量只在本轮循环有效 所以每次循环的i都是一个新的变量 js引擎内部会记住上一轮循环的值(每次循环i的值供后面执行函数时把本次循环的i赋给函数体的变量i),初始化本轮的变量i时(最后一步执行函数),就在上一轮循环的基础上进行计算。
这里还有一个for循环特殊的例子
for(let i = 0; i < 10; i++){
let i = 'abc';
console.log(i)
}
//abc
//abc
//abc
//打印了三个abc,可以看出小括号里定义的i和大括号里定义的i不在同一作用域,它们有各自独立的作用域
let不存在变量提升 也就是说不能在定义前使用变量
console.log(a);
var a = 123
// undefined
//用var定义的变量会提升到代码头部,在定义前使用会是undefined表示变量已定义但是还没赋值
---------------
console.log(a);
let a = 123
//报错
//而用let定义的变量不存在变量提升,在定义前使用会报错
暂时性死区 TDZ
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
只要代码块内有let定义变量 那么该变量不会被外部影响 上面例子中虽然外层有一个变量tmp 然后内部先对tmp进行了赋值 但是下面又用let定义了一个tmp 所以tmp变量被绑定在了该区块中 所以会报错。
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
暂时性死区也意味着typeof不是百分百不报错的操作了
typeof x; // ReferenceError
let x;
---------------------------
// 不报错
var x = x;
// 报错
let x = x;
//因为存在TDZ把x赋值给x 这个时候的x还是没有定义的状态 所以报错
// ReferenceError: x is not defined
不允许重复声明
let不允许在相同的作用域内声明同一个变量
function fn(){
var x = 123
let x = 234 //报错
}
-----------------------------
function fn(){
let x =123
let x =234 //报错
}
-----------------------------
function fn(x){
let x = 123
}
fn()//报错 因为重新声明了参数
-----------------------------
function fn(x){
{let x = 123}
}//不报错
const
const声明一个只读的常量。一旦声明,常量的值就不能改变。const和let的作用域相同,只在块级作用域内有效,并且也不存在变量提升,同样存在暂时性死区,也不可以重复声明
const hi = 123
hi //123
hi = 234 //报错
也就是说用const定义的变量必须在定义的时候就进行复制 否则会报错
const a
a = 123 //报错
const实质上并不是保证定义变量的值不变 而是指向内存地址所保存的数据不可变,对于Number、String、Boolean这种简单的数据类型 值就会保存在指向的那个内存地址 所以相当于常量 对于复合型数据 对象、数组const保存的是指向实际数据的指针 所以对于复合型数据内容可不可变是不能保证的
const复合型数据 对象 数组
const foo = {}
foo.name = 'jack' //成功
foo // foo{name : 'jack'}
const bar = {name : 'lisa'}
foo = bar //报错
从上面的例子可以看出 用const定义一个对象是可以在定义完后往里面添加新的数据,但是无法将新的对象赋值给原对象 数组也同理 看下面数组的例子
const arr = []
arr.push('study')
arr // ['stydy']
arr.length = 0
arr.length // 0
arr = ['play'] //报错