读懂ES6:let、const与解构赋值的深度解析
2024-08-10 09:24 阅读(269)

随着Web技术的飞速发展,JavaScript 作为前端开发的核心语言,也在不断进化。ECMAScript 作为JavaScript 的标准化规范,也在不断演进。ES6,即ECMAScript 6.0,是JavaScript发展历程中的一个重要里程碑,它引入了一系列革命性的新特性,极大地提升了JavaScript的编程效率和代码的可读性。


ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现,日常场合,这两个词是可以互换的。


本篇文章是在学习完阮一峰老师的 《ECMAScript 6 入门》一书后的学习总结,我将结合自身的理解和实践,通过详细的文字介绍与代码示例来帮助大家理解学习。这篇文章将探讨ES6中的几个关键特性,包括let与const、解构赋值,带你领略ES6的魅力。

let与const

ES6之前,JavaScript使用 var 关键字声明变量,但var声明的变量具有函数作用域或者全局作用域,而没有块级作用域。let和const的引入为JavaScript带来了块级作用域的概念,并解决了之前var关键字声明变量时存在的一些问题。

var声明变量的特性:


var 声明的变量具有函数作用域或者全局作用域

var 存在声明提升

var 可以重复声明变量


let和const声明变量的特性:


let与const 会和{}形成块级作用域,块级作用域是指变量或函数仅在它们被声明的块({})内部可见

let与const 声明的变量不能提升,也不出现在Windows。

let与const 不允许在相同作用域内,重复声明同一个变量。

const 声明一个只读的常量,声明后常量的值就不能改变。


const的不变性

使用const关键字声明的变量,其“不变性”主要体现在变量标识符与其所引用的内存地址之间的绑定关系上,而非变量本身所存储的值。

对于原始数据类型(如数值、字符串、布尔值),由于这些类型的值直接存储在变量所引用的内存地址中,因此const声明确保了这些值在初始化后不能被重新赋值给同一个变量标识符,从而在这些情况下,const声明的变量就等同于常量。

对于引用类型(如对象和数组),const声明的变量实际上是一个指向对象或数组在内存中位置的指针(引用)。这里的“不变性”指的是这个指针本身是不可变的,即你不能将变量重新指向一个新的对象或数组。但是,这并不意味着你不能修改对象或数组内部的状态或属性。

const abc = 123
// abc = 456     // 报错:Assignment to constant variable. 不能改变一个常量

const obj = { age: 18 };  
obj.age = 20;       // 修改对象的属性是被允许的  
console.log(obj);   // { age: 20 }  
  
const arr = [1, 2, 3];  
arr[1] = 'b';       // 修改数组的元素是被允许的  
console.log(arr);   // [1, "b", 3]  
  
// 但不能重新赋值给const声明的变量  
// obj = {};        // 报错:Assignment to constant variable.  
// arr = [];        // 报错:Assignment to constant variable.

暂时性死区

在变量声明之前,你不能访问该变量,即使是在同一作用域内。

块级作用域里有myname,JavaScript引擎就不会去访问全局的myname了,但是由于myname的声明在访问之前,形成了暂时性死区,于是报错:不能在声明myname之前访问它。

let myname = 'xx'
if(1) {
    console.log(myname);  // 报错:Cannot access 'myname' before initialization
    let myname = 'xx'     
}

解构

JavaScript的解构是一种表达式,它允许你直接从数组或对象中提取数据,并将其赋值给声明的变量。这种方式不仅减少了代码量,还使得从数据结构中提取数据变得更加直观和方便。

数组的解构

基本解构


不完全解构:不完全解构发生在数组的元素数量少于用于解构的变量数量时,在这种情况下,只有部分变量会被赋值,剩余的变量将被赋予undefined(如果它们没有默认值)。当然我们也可以设置默认值,默认值仅在数组缺少对应元素时才会被使用。

let arr = ['a','b']   // 二维数组
let [a,b,c,d=100] = arr
console.log(a,b,c,d);   // a b undefined 100

完全解构:完全解构就是数组的长度与用于解构的变量数量相匹配。

let arr = ['a','b',['c','d']]   // 二维数组
let [a,b,[c,d]] = arr
console.log(a,b,c,d);   // a b c d

扩展运算符

解构结合扩展运算符...,我们可以将数组中剩余的元素收集到一个新的数组中。在这个例子中,a 和 b分别被赋值为 1 和 2,而 c 则是一个包含剩余所有元素的数组[3, 4, 5]。

let arr = [1,2,3,4,5]
let [a,b,...c] = arr    // ...c是一个扩展运算符
console.log(c);         // [3,4,5]

对象的解构

在对象解构中可以直接根据对象的键来提取值。对于嵌套的对象比如第4行,需要在解构语法中嵌套相应的结构。

注意:c 是直接从obj中解构出来的,它引用了 obj 中的整个 c 对象。紧接着的c: { n }是一个并行解构,但它并不是重新声明一个名为c的变量,而是对已经解构出来的 c 对象进行进一步的解构,从中提取 n 属性并赋给同名的变量 n。

当对象的键和变量名相同时,我们可以省略: 变量名的部分,直接写出键名作为变量名,例如代码的第17行。

let obj = {
    a: 1,   // key为a ,值为1
    b: 2,
    c: {
        n: 3
    }
}
let {a, b, c, c:{n}} = obj
console.log(a,b,c,c.n);    // 1 2 { n: 3 } 3

// key和value重名,省略value不写
let user = {
    username: 'xx',
    age: 18
}
// let {username:username, age:age} = user 简写:
let {username, age} = user
console.log(username, age);    // xx 18

字符串的解构

字符串也是可以被解构,它被当作类似字符数组的对象处理。这里,a、b、c分别被赋值为字符串str的前三个字符,而d是一个包含剩余字符的数组。

let str = 'hello'
let [a,b,c,...d] = str
console.log(a,b,c,d);   // h e l ['l','o']