【03】ES6:解构赋值

一、数组的解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。

1、基本使用

遵循 “模式匹配” ,索引值相同的完成赋值

// 为变量赋值,只能直接指定值。
let a = 1
let b = 2
let c = 3

// 解构赋值:从数组中提取值,按照对应位置,对变量赋值。
let [a, b, c] = [1, 2, 3]
let [foo, [[bar], baz]] = [1, [[2], 3]]
foo // 1
bar // 2
baz // 3

let [ , , third] = ['foo', 'bar', 'baz']
third // 'baz'

let [x, , y] = [1, 2, 3]
x // 1
y // 3

let [head, ...tail] = [1, 2, 3, 4]
head // 1
tail // [2, 3, 4]

let [x, y, ...z] = ['a']
x // 'a'
y // undefined
z // []

2、默认值

(1)默认值的基本用法

const [a, b] = []
console.log(a, b) // undefined undefined

const [a = 1, b = 2] = []
console.log(a, b)    // 1 2

(2)默认值的生效条件

ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于 undefined,默认值才会生效。

const [a = 1, b = 2] = [3, 0] // 3 0
const [a = 1, b = 2] = [3, null] // 3 null
const [a = 1, b = 2] = [3] // 3 2

const [x = 1] = [undefined] // 1
const [x = 1] = [null] // null

(3)默认值表达式

如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。

// x 能取到值,所以函数 f 根本不会执行
function f() {
    
    
	console.log('aaa')
}

let [x = f()] = [1]

(4)默认值引用

默认值可以引用解构赋值的其他变量,但该变量必须已经声明。

let [x = 1, y = x] = [] // 1 1
let [x = 1, y = x] = [2] // 2 2
let [x = 1, y = x] = [1, 2] // 1 2
let [x = y, y = 1] = [] // ReferenceError: Cannot access 'y' before initialization (x 用 y 做默认值时,y 还没有声明)

3、数组解构赋值的应用

(1)类数组对象 arguments

function func() {
    
    
	const [a, b] = arguments
    console.log(a, b)    // 1 2
}
func(1, 2)

(2)NodeList

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>NodeList</title>
</head>
<body>
<p>1</p>
<p>2</p>
<p>3</p>
<script>
    const [p1, p2, p3] = document.querySelectorAll('p')
    console.log(p1, p2, p3)
    /*
    <p>1</p>
    <p>2</p>
    <p>3</p>
    */
</script>
</body>
</html>

(3)函数参数的解构赋值

const array = [1, 1]
// const add = arr => arr[0] + arr[1]
const add = ([x = 0, y = 0]) => x + y
console.log(add(array)) // 2
console.log(add([])) // 0
[[1, 2], [3, 4]].map(([a, b]) => a + b)
// [ 3, 7 ]

(4)交换变量的值

let x = 2, y = 1

// 原来
let tmp = x
x = y
y = tmp

// 现在
[x, y] = [y, x] // [x, y] = [1, 2]
console.log(x, y) // 1 2

(5)跳过某项值使用逗号隔开

在解构数组时,可以忽略不需要解构的值,可以使用逗号对解构的数组进行忽略操作,这样就不需要声明更多的变量去存值了:

var [a, , , b] = [10, 20, 30, 40]
console.log(a) // 10
console.log(b) // 40

(6)剩余参数中的使用

通常情况下,需要把剩余的数组项作为一个单独的数组,这个时候我们可以借助展开语法把剩下的数组中的值,作为一个单独的数组,如下:

var [a, b, ...rest] = [10, 20, 30, 40, 50]
console.log(a) // 10
console.log(b) // 20
console.log(rest) // [30, 40, 50]

在 rest 的后面不能有 逗号 不然会报错,程序会认出你后面还有值。…rest 是剩余参数的解构,所以只能放在数组的最后,在它之后不能再有变量,否则则会报错。

二、对象的解构赋值

1、基本使用

对象的解构和数组基本类似,对象解构的变量是在 {} 中定义的。

遵循 “模式匹配” ,属性名相同的完成赋值。

// 对象没有索引,但对象有更明确的键,通过键可以很方便地去对象中取值
let {
    
     foo, bar } = {
    
     foo: 'aaa', bar: 'bbb' }
foo // 'aaa'
bar // 'bbb'

let {
    
     bar, foo, baz } = {
    
     foo: 'aaa', bar: 'bbb' }
foo // 'aaa'
bar // 'bbb'
baz // undefined

如果变量名与属性名不一致,必须写成下面这样。

// foo 是匹配的模式,baz 才是变量。真正被赋值的是变量 baz,而不是模式 foo。
let {
    
     foo: baz } = {
    
     foo: 'aaa', bar: 'bbb' }
baz // 'aaa'
foo // error: foo is not defined

2、默认值

默认值生效的条件是,对象的属性值严格等于 undefined。

如果默认值是表达式,默认值表达式是惰性求值的。

var {
    
     a = 10, b = 5 } = {
    
     a: 3 } // a = 3, b = 5
var {
    
     a = 10, b = 5 } = {
    
     a: 3, b: undefined } // a = 3, b = 5
var {
    
     a = 10, b = 5 } = {
    
     a: 3, b: null } // a = 3, b = null

3、对象解构赋值的应用

(1)对象作为函数参数

// 之前
const logPersonInfo = user => console.log(user.name, user.age)
logPersonInfo({
    
     name: 'jerry', age: 18 }) // jerry 18

// 之后
const logPersonInfo = ({
    
     age = 21, name = 'tom' }) => console.log(name, age);
logPersonInfo({
    
    name: 'jerry', age: 18}) // jerry 18
logPersonInfo({
    
    }) // tom 21

(2)从函数返回多个值

// 返回一个数组
function example() {
    
    
	return [1, 2, 3]
}
let [a, b, c] = example()

// 返回一个对象
function example() {
    
    
	return {
    
    
		foo: 1,
		bar: 2
	}
}
let {
    
     foo, bar } = example()

(3)复杂嵌套(多重解构赋值)

let obj = {
    
    
	p: [
		'Hello',
		{
    
     y: 'World' }
	]
}

// 这时 p 是模式,不是变量,因此不会被赋值。
let {
    
     p: [x, {
    
     y }] } = obj
x // 'Hello'
y // 'World'

// p 作为变量赋值
let {
    
     p, p: [x, {
    
     y }] } = obj
x // 'Hello'
y // 'World'
p // ['Hello', {y: 'World'}]
const node = {
    
    
	loc: {
    
    
		start: {
    
    
			line: 1,
			column: 5
		}
	}
}
// 三次解构赋值,分别是对 loc、start、line 三个属性的解构赋值。
// 注意,最后一次对 line 属性的解构赋值之中,只有 line 是变量,loc 和 start 都是模式,不是变量.
let {
    
     loc, loc: {
    
     start }, loc: {
    
     start: {
    
     line }} } = node
line // 1
loc  // Object {start: Object}
start // Object {line: 1, column: 5}

(4)剩余参数中的使用

在对象的解构中也可以使用剩余参数,对象中没有解构的剩余属性做聚合操作,生成一个新的对象。

const {
    
     a, c, ...rest } = {
    
     a: 1, b: 2, c: 3, d: 4 }
console.log(a)     // 1
console.log(c)     // 3
console.log(rest)  // { b: 2, d: 4 }

4、注意点

(1)如果要将一个已经声明的变量用于解构赋值,必须非常小心。

// 错误的写法
let x
{
    
     x } = {
    
     x: 1 }
// SyntaxError: syntax error

上面代码的写法会报错,因为 JavaScript 引擎会将 {x} 理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。

// 正确的写法
let x
({
    
     x } = {
    
     x: 1 })

上面代码将整个解构赋值语句,放在一个圆括号里面,就可以正确执行。

(2)解构赋值允许等号左边的模式之中,不放置任何变量名。因此,可以写出非常古怪的赋值表达式。

({
    
    } = [true, false])
({
    
    } = 'abc')
({
    
    } = [])

上面的表达式虽然毫无意义,但是语法是合法的,可以执行。

(3)由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。

let arr = [1, 2, 3]
let {
    
     0 : first, [arr.length - 1] : last } = arr
first // 1
last // 3

上面代码对数组进行对象解构。数组arr的0键对应的值是1,[arr.length - 1]就是2键,对应的值是3。

三、字符串的解构赋值

字符串也可以解构赋值。既可以用数组的形式来解构赋值,也可以用对象的形式来解构赋值。

// 数组形式解构赋值
const [a, b, , , c] = 'hello'
console.log(a, b, c) // h e o

// 对象形式解构赋值
// 类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。
const {
    
     0: a, 1: b, 4: o, length : len } = 'hello'
console.log(a, b, o, len) // h e o 5

四、数值和布尔值的解构赋值

只能按照对象的形式来解构赋值。(先自动将等号右边的值转为对象)

// 转化后的对象里没有任何的属性(没有 123 这个属性,也没有 true 这个属性)和方法,
// 所有的属性和方法都在它的继承 __proto__ 中,比如 toString 方法就是继承来的。
new Number(123)
new Boolean(true)

// 里面的值只能是默认值,继承的方法倒是可以取到
const {
    
     a = 1, toString: s } = 123
console.log(a, s) // 1 [Function: toString]

// 里面的值只能是默认值,继承的方法倒是可以取到
const {
    
     b = 1, toString } = true;
console.log(b, toString) // 1 [Function: toString]

五、undefined 和 null 没有解构赋值

解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于 undefined和 null 无法转为对象,所以对它们进行解构赋值,都会报错。

let {
    
     prop: x } = undefined // TypeError
let {
    
     prop: y } = null // TypeError

猜你喜欢

转载自blog.csdn.net/weixin_45559449/article/details/134579983