Javascript ES6 展开语法和解构赋值语法
date
May 15, 2020
slug
5589753342289920
status
Published
tags
summary
type
Post
展开语法
展开语法(Spread syntax), 可以在函数调用或数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造字面量对象时, 将对象表达式按键值的方式展开。
函数参数展开
function fun(a, b, c) { console.log(a, b, c) } let args = [1, 2, 3] fun(...args) // 1 2 3function fun1(a, b, c, d) { console.log(a, b, c, d) } let args = [2, 3] fun1(1, ...args, 4) // 1 2 3 4
数组使用展开语法
let array1 = [1, 2, 3] let array2 = ['hello', ...array1] console.log(array2) // ["hello", 1, 2, 3]
数组的深拷贝
let array1 = [1, 2, 3] let array2 = array1 let array3 = [...array1] array2.push(4);array3.push(5) console.log(array1) // [1, 2, 3, 4]console.log(array2) // [1, 2, 3, 4]console.log(array3) // [1, 2, 3, 5]
对象开展语法
let obj1 = { foo: 'bar', x: 42 } let obj2 = { foo: 'baz', y: 13 } let clonedObj = { ...obj1 } // 克隆后的对象: { foo: "bar", x: 42 }let mergedObj = { ...obj1, ...obj2 } // 合并后的对象: { foo: "baz", x: 42, y: 13 }
扩展
剩余语法(剩余参数):
剩余语法(Rest syntax) 看起来和展开语法完全相同,不同点在于, 剩余参数用于解构数组和对象。从某种意义上说,剩余语法与展开语法是相反的:展开语法将数组展开为其中的各个元素,而剩余语法则是将多个元素收集起来并“凝聚”为单个元素。
function fun(a, b, ...theArgs) { console.log(a, b, theArgs) } fun(1, 2, 3, 4, 5) // 1 2 [3, 4, 5]
剩余参数和
arguments
对象之间的区别主要有三个:剩余参数只包含那些没有对应形参的实参,而 arguments 对象包含了传给函数的所有实参。arguments对象不是一个真正的数组,而剩余参数是真正的 Array实例,也就是说你能够在它上面直接使用所有的数组方法,比如 sort,map,forEach或pop。arguments对象还有一些附加的属性 (如callee属性)。
解构赋值
通过解构赋值, 可以将属性或值从对象或数组中取出,赋值给其他变量。
解构数组是将取值数组的元素与变量数据相对应,将数组中位置一致的值赋值给等号左边位置相同的变量。
解构对象是将相同键的对象相对应进行解构赋值。
let a, b, c // 数组形式解构(解构数组) ↓let [a, b] = [1, 2] // 变量声明并赋值时的解构[a, b] = [1, 2] // 变量先声明后赋值时的解构console.log(a, b) // 1 2[a, b] = [1, 2, 3, 4] console.log(a, b) // 1 2[a, b, ...c] = [1, 2, 3, 4, 5] console.log(a, b, c); // 1 2 [1, 2, 3, 4, 5]// 对象形式结构(解构对象) ↓let {a, b} = {a: 10, b: 20} // 声明解构赋值console.log(a, b); // 10 20({a, b} = {a: 10, b: 20}) // 无声明解构赋值console.log(a, b); // 10 20({a, b, ...c} = {a: 10, b: 20, c: 30, d: 40, e: 50}) // Rest剩余参数语法(展开语法)console.log(a, b, c) // 10 20 {c: 30, d: 40, e: 50}
注意:赋值语句周围的圆括号( ... )
在使用对象无声明解构赋值时是必须的。{a, b} = {a: 10, b: 20}
不是有效的独立语法,因为左边的{a, b}
被认为是一个块而不是对象字面量。然而,({a, b} = {a: 1, b: 2})
是有效的,正如var {a, b} = {a: 1, b: 2}
。需要注意的是( ... )
表达式之前需要有一个分号,否则它可能会被当成上一行中的函数执行。let a, b console.log('hello') ({a, b} = {a:1, b:2}) console.log(a, b) // Uncaught TypeError: console.log(...) is not a function
以下是不正确的赋值方法:// 错误的赋值方法 ↓let c = {a: 1, b: true} let a, b {a, b} = c // Uncaught SyntaxError: Unexpected token '='// 正确的赋值方法 ↓let c = {a: 1, b: true} let {a, b} = c // 或let c = {a: 1, b: true} let a, b ({a, b} = c)
如果( ... )
表达式是没有声明时赋值的,则有无分号都无影响。
解构赋值中为了防止从数组取值为
undefined
提供里默认值,说白了就是为了防止变量数量少于取值数组数量时来为多余的变量赋予默认值。let a, b [a, b] = [1] console.log(a, b) // 1 undefined[a, b=2] = [1] console.log(a, b) // 1 2let {a, b = 5} = {a: 1};console.log(a, b); // 1 5
此外利用解构赋值语法可以更简便的交换变量
let a=1, b=2console.log(a, b) // 1 2[a, b] = [b, a] console.log(a, b) // 2 1
忽略部分值
let a, b [a,, b] = [1, 2, 3] console.log(a, b) // 1 3
当然,你可以忽略所有值,不过这好像并没有什么意义
[,,] = [1, 2, 3]
解构对象给新的变量名赋值
let c = {a: 1, b: true};let {a: foo, b: bar} = c;console.log(foo, bar); // 1 true
解构对象给新的变量名赋值并提供默认值
var {a:foo, b:bar = 5} = {a: 3};console.log(foo, bar); // 3 5
扩展
解构嵌套对象和数组
const metadata = { title: 'Scratchpad', translations: [ { locale: 'de', localization_tags: [], last_edit: '2014-04-14T08:43:37', url: '/de/docs/Tools/Scratchpad', title: 'JavaScript-Umgebung' } ], url: '/en-US/docs/Tools/Scratchpad'};let { title: englishTitle, // rename translations: [ { title: localeTitle, // rename }, ],} = metadata;console.log(englishTitle); // "Scratchpad"console.log(localeTitle); // "JavaScript-Umgebung"
For of 迭代和解构
let people = [ { name: 'Mike Smith', family: { mother: 'Jane Smith', father: 'Harry Smith', sister: 'Samantha Smith' }, age: 35 }, { name: 'Tom Jones', family: { mother: 'Norah Jones', father: 'Richard Jones', brother: 'Howard Jones' }, age: 25 } ];for (var {name: n, family: {father: f}} of people) { console.log('Name: ' + n + ', Father: ' + f);} // "Name: Mike Smith, Father: Harry Smith"// "Name: Tom Jones, Father: Richard Jones"
从作为函数实参的对象中提取数据
function userId({id}) { return id;} function whois({displayName: displayName, fullName: {firstName: name}}){ console.log(displayName + " is " + name);} let user = { id: 42, displayName: "jdoe", fullName: { firstName: "John", lastName: "Doe" } };console.log("userId: " + userId(user)); // "userId: 42"whois(user); // "jdoe is John"
从ECMAScript 2015开始,对象初始化语法开始支持计算属性名。其允许在[]中放入表达式,计算结果可以当做属性名。计算属性名可以被解构。
let key = "z";let {[key]: foo} = {z: "bar"};console.log(foo); // "bar"