[TOC] #### 1.解构赋值 --- 对象中有很多数据,现在我们需要从对象中取出某些数据赋值给指定变量 ```javascript const user = { name: "辰风沐阳", age: 20, gender: '男', height: 180, weight: 130 } ``` 在 ES6 之前,获取对象中的某些值,需要通过 `对象.属性名` 获取 ```javascript let name = user.name let gender = user.gender let weight = user.weight ``` 如果需要获取的属性很多时,要写大量 `.` 来获取,这种方式显然不够简洁美观,我们需要一种更优雅的写法 ES6 引入了很多新特性,其中之一就是解构。直接从对象或数组中批量提取值,并将值赋给变量,从而使代码更加简洁易读 ```javascript let { name, gender, weight } = user ``` #### 2.对象解构 --- 最基础的用法:同名变量解构赋值,只提取需要的值,并且赋给变量 ```javascript const user = { name: "liang", age: 20, height: 180 } let { name, age } = user console.log({ name, age }); // { name: 'liang', age: 20 } ``` 也支持给解构出来的属性指定新的变量名称,使用 `:` 即可指定新的变量名 ```javascript const user = { name: "liang", age: 20, height: 180 } let { name: userName } = user console.log(userName); // liang ``` 如果解构的变量,在对象中没有同名属性,那么该变量会被赋值为 undefined,可以使用 `=` 指定解构的默认值 ```javascript const user = { name: "liang" } let { age } = user console.log(age); // undefined const user = { name: "liang" } let { age = 20 } = user // 使用 “=” 可以指定解构的默认值 console.log(age); // 20 ``` 对于多层对象的解构,可以深入到嵌套的对象结构中去提取想要的数据,同样支持指定新的变量名、解构默认值 ```javascript const user = { name: "liang", info: { weight: 70, height: 180 } } let { info: { weight, height: length } } = user console.log({ weight, length }); // { weight: 70, length: 180 } ``` #### 3.数组解构 --- 数组解构的语法和对象解构的语法非常相似,只是将对象字面量替换为了数组字面量 + 对象解构:作用在对象的具名属性上,解构时关注属性名称 + 数组解构:作用在数组的元素位置上,解构时关注元素位置 数组解构基础用法:按照元素的位置,依次赋值给指定变量 ```javascript const [a, b] = ['red', 'green', 'blue'] console.log(a); // red console.log(b); // green ``` 如果不想解构某些值,可以使用逗号直接略过,数组解构也可以使用 `=` 指定解构的默认值 ```javascript const [a, , b] = ['red', 'green', 'blue'] console.log(a); // red console.log(b); // blue const [, , c] = ['red', 'green', 'blue'] console.log(c); // blue const [, d = 'purple'] = ['red'] console.log(d); // purple ``` 剩余项解构:先解构部分,然后将剩余项全部解构到一个变量。使用 `...` 将剩余项目赋值给指定的一个变量 ```javascript const [a, ...b] = ['red', 'green', 'blue'] console.log(a); // red console.log(b); // ['green', 'blue'] ``` #### 4.参数解构 --- 参数解构是指在函数定义时,直接从传入的参数中解构出所需要的属性,使代码更简洁、更具可读性 对象参数解构:当函数接收一个对象作为参数时,可以在函数参数中使用对象解构,提取所需属性 ```javascript // 只需要用到 id 和 age,那么可以只将它们解构出来,同样也支持设置默认值 function getInfo({ id, age = 20 }) { console.log({ id, age }); // { id: 10, age: 20 } } // 对象中传递多个值 getInfo({ id: 10, name: 'liang', height: 180 }); ``` 实际开发中,前端有些下拉框数据需要从后端接口获取,但是接口返回的列表数据字段有很多,并且字段名和我们组件需要的字段名不一致。那么我们可以将接口返回的数据重新构建为我们需要的结构,此时就会用到 Array.map() 方法 ```javascript const lists = [ { id: 1, name: 'html', score: 70, create_time: 1769390831 }, { id: 2, name: 'css', score: 85, create_time: 1769390845 }, { id: 3, name: 'javascript', score: 100, create_time: 1769390849 }, ] // 普通写法 const ids1 = lists.map(item => ({ value: item.id, label: item.name })) // 解构写法 const ids2 = lists.map(({ id: value, name: label }) => ({ value, label })) ``` 对象参数解构,在实际开发中是非常多的,下面是在 Vuex 中使用对象参数解构的场景 ```javascript const store = new Vuex.Store({ actions: { update(context) { // 通过打印可以发现 context 对象上有 state getters commit dispatch 等属性 // 但是,我们可能只使用到其中某些属性,比如:只需要用到 context.commit 属性 console.log(context); }, // 对象参数解构用法示例 getUser({ commit }) { return new Promise(resolve => { uni.$u.http.get('/auth/info').then(res => { if (res.code == 200) { commit('SET_USERINFO', res.data) } resolve() }) }) }, } }) ``` 还可以用于封装功能函数,配置项处理等场景,让函数更灵活,易于扩展 ```javascript function request({ url, method = 'GET', params = {}, data = {} }) { // 执行请求逻辑 } ``` 数组参数解构:当函数接收一个数组作为参数时,也可以在函数参数中使用数组解构 ```javascript function sum([a, b]) { return a + b } console.log(sum([1, 2])); ``` #### 5.可迭代对象 --- ##### 可迭代协议 通常情况下,我们都是对数组进行数组解构,对象进行对象解构。但是,对象能进行数组解构吗 ? ```javascript // 将一个对象进行数组解构,此时会报错 let [a, b] = { a: 3, b: 4 } // 报错信息如下所示,意思是 intermediate value 不是一个可迭代的东西 // Uncaught TypeError: {(intermediate value)(intermediate value)} is not iterable ``` 那么,如何能将对象能进行数组解构,使上面代码成立呢 ?这是也是一个常见的面试题 ```javascript // 面试题:让下面的代码成立 let [a, b] = { a: 3, b: 4 } ``` 首先,我们要明白一个概念,什么是可迭代对象 ? 可迭代对象:是指满足可迭代协议的对象,可迭代协议是对象中函数名为 `Symbol.iterator` 的成员 ```javascript let data = { a: 3, b: 4, // 可迭代协议 [Symbol.iterator]() { return '迭代器' } } ``` ##### 数组解构的本质 所以解构时右边只要放一个可迭代的对象就可以了,数组解构时右边通常放的是一个数组,说明数组就是可迭代对象 ```javascript const arr = [3, 4] // 可以看到数组确实有 Symbol.iterator 属性,并且它是一个函数 console.log(arr[Symbol.iterator]); // ƒ values() { [native code] } // 可迭代协议函数的返回值是一个迭代器 const iter = arr[Symbol.iterator]() console.log(iter); // 返回一个对象 // next() 表示得到下一项 console.log(iter.next()); // {value: 3, done: false} console.log(iter.next()); // {value: 4, done: false} ``` 所以,我们可以得到结论: ```javascript const arr = [3, 4] // 以下代码 // let [a, b] = arr // 等同于 const iter = arr[Symbol.iterator]() let a = iter.next().value let b = iter.next().value ``` 以下为面试题答案,就是给对象增加可迭代协议,使其支持数组解构。[JavaScript 迭代器和生成器](https://www.itqaq.com/index/681.html) ```javascript // 面试题:让下面的代码成立 let [a, b] = { a: 3, b: 4 } // 在 Object.prototype 的原型上添加迭代器 Object.prototype[Symbol.iterator] = function () { // this 为当前对象数据,如:{ a: 3, b: 4 } return Object.values(this)[Symbol.iterator]() } // 简化版:使用 ES6 的生成器(可以将上面代码改造成以下生成器写法) Object.prototype[Symbol.iterator] = function* () { yield* Object.values(this) } ``` #### 6.交换两个变量 --- 面试中被问到如何交换两个变量的值,就是在考察是否能想到用解构赋值交换。[如何交换两个变量](https://www.itqaq.com/index/68.html) 使用解构赋值交换变量,相对于传统的临时变量,代码更加简洁、已读,并且不受运算法交换的局限性 ```javascript // ; 不能省略,否则解构时左侧会被当作字面量,进而导致报错 let a = 1; let b = 2; [a, b] = [b, a]; ```