大家好,我们学习的是ES6也就是 ES2015这样的一个版本,我们一起来学一下在ES6里面都有哪些新特性可以供我们去使用。
在ES5 和 ES5之前我们使用的声明方式叫 var,为什么在有var 的情况下又推出了let 跟const呢?三者有什么区别呢?下面我们来一起看一下吧。
1. 顶层对象window
// 大家看以下代码都是正常输出,那写var跟不写var两者到底有什么区别呢?
var a = 1
console.log(a) // 1
b = 2
console.log(b) // 2
- 当我们使用 var 关键字定义的一个变量的时候,相当于在当前的作用域内声明的一个变量
- 不使用var的话相当于是一个属性进行赋值,在window这个全局对象上面定义了一个属性叫做b
下面我们使用 delete 删除一下对象的属性验证一下 (delete 只能删除对象的属性,并不能删除变量)
var a = 1
delete a
console.log(a) // 1
b = 2
delete b
console.log(b) // b is not defind
- 以上我们看到使用 delete 之后 使用 var 声明的变量还存在, 而未使用 var 声明的变量提示 b is not defind,说明不使用var 直接声明的变量是一个全局对象上面的属性
下面我们再看一段代码
var a = 1
console.log(window.a) // 1
b = 2
console.log(window.b) // 2
为什么var 声明的变量也会出现在window 上面呢?
- 这个是因为JS作者在设计初期的时候,把顶层对象的属性和全局变量进行了挂钩,这个被很多人认为这是JS语言最大的设计败笔之一。
下面我们使用let 来看一下这个问题
let a = 1
console.log(a) // 1
console.log(window.a) // undefined
- let 弥补了 var 对全局变量和顶层对象的属性进行挂钩的问题
- 由此我们得出 let 定义的变量不属于顶层对象 window,也不会出现引起污染全局变量这样的问题
2. 对象的重复声明
var 是允许重复声明的,而且后定义的会把先定义的覆盖掉,下面我们来输出看一下
var a = 11
var a = 22
console.log(a) // 22
下面我们换成 let 看一下
let a = 11
let a = 22
console.log(a) // Identifier 'a' has already been declared
我们看到控制台报错了,提示 a 这样的修饰符已经被定义过。
- let 不允许重复声明变量
3. 变量提升
var 定义的变量具有变量提升
console.log(a) // undefined
var a = 11
// -----相当于先定义了一个变量 a 并没有赋值,下面对 a 再进行一个赋值-----
var a
console.log(a)
a = 11
下面我们换成 let 看一下
console.log(a) // Cannot access 'a' before initialization
let a = 11
我们看到控制台报错了,提示初始化前不能访问 a
- let 定义的变量不存在变量提升
4. 块级作用域
在 var 定义的变量并没有块级作用域,一个{} 就可以形成一个块级作用域,相当于我在这{}定义的变量,只能在这一块使用。
下面我们来用代码演示一下
for(var i = 0; i < 3; i++){
console.log(i) // 0, 1, 2
}
console.log(i) // 3
- 在ES 5 里面只有全局作用域和函数作用域没有块级作用域,所以说在循环外面可以取到 i,并且是循环结束之后的 i ,所以 i 的值为 3
下面我们换成 let 看一下
for(let i = 0; i < 3; i++){
console.log(i) // 0, 1, 2
}
console.log(i) // i is not defined
- let 具有块级作用域
let
- 不属于顶层对象 window
- 不允许重复声明
- 不存在变量提升
- 块级作用域
- 暂时性死区(所有的变量必须要先定义再去使用)
const
使用 const 定义常量,用于声明常量,常量不允许被修改
- 定义的变量不属于顶层对象 window
- 不允许重复声明
- 不存在变量提升
- 同样也是具有块级作用域的
- 常量声明后不可修改
- 必须声明时候赋值
// ---------定义的变量不属于顶层对象 window---------
let a = 1
console.log(a) // 1
console.log(window\.a) // undefined
// ---------不允许重复声明---------
const a = 11
const a = 22
console.log(a) // Identifier 'a' has already been declared
// ---------不存在变量提升---------
console.log(a) // Cannot access 'a' before initialization
const a = 11
// ---------具有块级作用域---------
{
const a = 1
}
console.log(a) // a is not defined
// ---------常量声明后不可修改---------
const a = 1
a = 2 // Assignment to constant variable.
// ---------必须声明时候赋值---------
const a
a = 2 // Missing initializer in const declaration
如果我们使用const 定义引用类型会有什么效果呢?
const obj = {
name: "小白",
age: 4,
}
console.log(obj) // {name: '小白', age: 4}
obj.color = '黑色'
console.log(obj) // {name: '小白', age: 4, color: '黑色'}
const 不是定义的常量吗?不是不能被改变吗?为什么还能添加 color 呢? 首先我们要先明白两个概念:
- 基本数据类型是存储在栈内存的
- 引用数据类型是存在堆内存里面的,在栈内存里面存的是一个引用的地址,指向堆内存
所以变量指向的栈内存的引用地址并没有改变,改变的只不过是堆内存里面的存的内容
什么时候使用let? 什么时候使用const 呢?
当你定义当前值的时候需要考虑一下,在后面的逻辑中是否会改变 如果当前这个值在后面要进行逻辑业务的运算,要给他赋一个新的值,就使用 let 如果这个值一直是初始值,不会被改变的情况下是就用const