3.1 数组的解构赋值
3.1.1 基本用法
ES6 允许按照一定模式从数组和对象中提取值,然后对变量进行赋值,这被称为解构(Destructuring)。
以前,为变量赋值只能直接指定值。
| |
| |
| let hzh1 = 1; |
| let hzh2 = 2; |
| let hzh3 = 3; |
ES6允许写成下面这样。
| |
| |
| let [hzh1, hzh2, hzh3] = [1, 2, 3]; |
上面的代码表示,可以从数组中提取值,按照对应位置对变量赋值。
本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。下面是一些使用嵌套数组进行解构的例子。
| |
| |
| let [hzh1, [[hzh2], hzh3]] =[ 1,[[2], 3] ]; |
| console.log("hzh1 = " + hzh1); |
| console.log("hzh2 = "+ hzh2); |
| console.log("hzh3 = " + hzh3); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| hzh1 = 1 |
| hzh2 = 2 |
| hzh3 = 3 |
| |
| [Done] exited with code=0 in 0.173 seconds |
| |
| |
| let [ , , third ,] = ["尤雨溪", "人世间", "黄子涵"]; |
| console.log("third = " + third); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| third = 黄子涵 |
| |
| [Done] exited with code=0 in 0.83 seconds |
| |
| |
| let [hzh1, , hzh3] = [1, 2, 3]; |
| console.log("hzh1 = " + hzh1); |
| console.log("hzh3 = " + hzh3); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| hzh1 = 1 |
| hzh3 = 3 |
| |
| [Done] exited with code=0 in 0.205 seconds |
| |
| |
| let [hzh1, ...hzh2] = [1, 2, 3, 4]; |
| console.log("输出hzh1的值:"); |
| console.log(hzh1); |
| console.log("输出hzh2的值:"); |
| console.log(hzh2); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| 输出hzh1的值: |
| 1 |
| 输出hzh2的值: |
| [ 2, 3, 4 ] |
| |
| [Done] exited with code=0 in 0.179 seconds |
| |
| |
| let [hzh1, hzh2, ...hzh3] = ['黄子涵']; |
| console.log("输出hzh1的值:"); |
| console.log(hzh1); |
| console.log("输出hzh2的值:"); |
| console.log(hzh2); |
| console.log("输出hzh3的值:"); |
| console.log(hzh3); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| 输出hzh1的值: |
| 黄子涵 |
| 输出hzh2的值: |
| undefined |
| 输出hzh3的值: |
| [] |
| |
| [Done] exited with code=0 in 0.201 seconds |
如果解构不成功,变量的值就等于undefined。
| |
| |
| let [hzh1] = []; |
| let [hzh2, hzh3] = [1]; |
| console.log("hzh1 = "+ hzh1); |
| console.log("hzh2 = "+ hzh2); |
| console.log("hzh3 = "+ hzh3); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| hzh1 = undefined |
| hzh2 = 1 |
| hzh3 = undefined |
| |
| [Done] exited with code=0 in 0.198 seconds |
以上两种情况都属于解构不成功,hzh和hzh3的值都会等于undefined。
另一种情况是不完全解构,即等号左边的模式只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。
| |
| |
| let [hzh1, hzh2] = [1, 2, 3]; |
| let [hzh3, [hzh4], hzh5] = [3, [4, '不解构'], 5]; |
| console.log("hzh1 = "+ hzh1); |
| console.log("hzh2 = "+ hzh2); |
| console.log("hzh3 = "+ hzh3); |
| console.log("hzh4 = "+ hzh4); |
| console.log("hzh5 = "+ hzh5); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| hzh1 = 1 |
| hzh2 = 2 |
| hzh3 = 3 |
| hzh4 = 4 |
| hzh5 = 5 |
| |
| [Done] exited with code=0 in 0.226 seconds |
上面两个例子都属于不完全解构,但是可以成功。
如果等号的右边不是数组(或者严格来说不是可遍历的结构),那么将会报错。
| |
| |
| |
| let [hzh1] = 1; |
| console.log(hzh1); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| e:\HMV\Babel\hzh.js:4 |
| let [hzh1] = 1 |
| ^ |
| |
| TypeError: 1 is not iterable |
| at Object.<anonymous> (e:\HMV\Babel\hzh.js:4:14) |
| at Module._compile (internal/modules/cjs/loader.js:999:30) |
| at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10) |
| at Module.load (internal/modules/cjs/loader.js:863:32) |
| at Function.Module._load (internal/modules/cjs/loader.js:708:14) |
| at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12) |
| at internal/main/run_main_module.js:17:47 |
| |
| [Done] exited with code=1 in 0.168 seconds |
| |
| |
| |
| let [hzh2] = false; |
| console.log(hzh2); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| e:\HMV\Babel\hzh.js:4 |
| let [hzh2] = false |
| ^ |
| |
| TypeError: false is not iterable |
| at Object.<anonymous> (e:\HMV\Babel\hzh.js:4:14) |
| at Module._compile (internal/modules/cjs/loader.js:999:30) |
| at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10) |
| at Module.load (internal/modules/cjs/loader.js:863:32) |
| at Function.Module._load (internal/modules/cjs/loader.js:708:14) |
| at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12) |
| at internal/main/run_main_module.js:17:47 |
| |
| [Done] exited with code=1 in 0.169 seconds |
| |
| |
| |
| let [hzh3] = NaN; |
| console.log(hzh3); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| e:\HMV\Babel\hzh.js:4 |
| let [hzh3] = NaN |
| ^ |
| |
| TypeError: NaN is not iterable |
| at Object.<anonymous> (e:\HMV\Babel\hzh.js:4:14) |
| at Module._compile (internal/modules/cjs/loader.js:999:30) |
| at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10) |
| at Module.load (internal/modules/cjs/loader.js:863:32) |
| at Function.Module._load (internal/modules/cjs/loader.js:708:14) |
| at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12) |
| at internal/main/run_main_module.js:17:47 |
| |
| [Done] exited with code=1 in 0.194 seconds |
| |
| |
| |
| let [hzh4] = undefined; |
| console.log(hzh4); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| e:\HMV\Babel\hzh.js:4 |
| let [hzh4] = undefined |
| ^ |
| |
| TypeError: undefined is not iterable |
| at Object.<anonymous> (e:\HMV\Babel\hzh.js:4:14) |
| at Module._compile (internal/modules/cjs/loader.js:999:30) |
| at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10) |
| at Module.load (internal/modules/cjs/loader.js:863:32) |
| at Function.Module._load (internal/modules/cjs/loader.js:708:14) |
| at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12) |
| at internal/main/run_main_module.js:17:47 |
| |
| [Done] exited with code=1 in 0.186 seconds |
| |
| |
| |
| let [hzh5] = null; |
| console.log(hzh5); |
| [Running] node "e:\HMV\Babel\tempCodeRunnerFile.js" |
| e:\HMV\Babel\tempCodeRunnerFile.js:4 |
| let [hzh5] = null |
| ^ |
| |
| TypeError: null is not iterable |
| at Object.<anonymous> (e:\HMV\Babel\tempCodeRunnerFile.js:4:14) |
| at Module._compile (internal/modules/cjs/loader.js:999:30) |
| at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10) |
| at Module.load (internal/modules/cjs/loader.js:863:32) |
| at Function.Module._load (internal/modules/cjs/loader.js:708:14) |
| at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12) |
| at internal/main/run_main_module.js:17:47 |
| |
| [Done] exited with code=1 in 0.169 seconds |
| |
| |
| |
| let [hzh6] = {}; |
| console.log(hzh6); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| e:\HMV\Babel\hzh.js:4 |
| let [hzh6] = {} |
| ^ |
| |
| TypeError: {} is not iterable |
| at Object.<anonymous> (e:\HMV\Babel\hzh.js:4:14) |
| at Module._compile (internal/modules/cjs/loader.js:999:30) |
| at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10) |
| at Module.load (internal/modules/cjs/loader.js:863:32) |
| at Function.Module._load (internal/modules/cjs/loader.js:708:14) |
| at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12) |
| at internal/main/run_main_module.js:17:47 |
| |
| [Done] exited with code=1 in 0.17 seconds |
上面的语句都会报错,因为等号右边的值或是转为对象以后不具备 Iterator 接口(前五个表达式),或是本身就不具备 Iterator 接口(最后一个表达式)。
对于 Set 结构,也可以使用数组的解构赋值。
| |
| |
| let [hzh1, hzh2, hzh3] = new Set(['黄子涵', '尤雨溪', '人世间']); |
| console.log("hzh1 = " + hzh1); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| hzh1 = 黄子涵 |
| |
| [Done] exited with code=0 in 0.506 seconds |
事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。
| |
| |
| function* fibs() { |
| let hzh1 = 1; |
| let hzh2 = 2; |
| while(true) { |
| yield hzh1; |
| [hzh1, hzh2] = [hzh2, hzh1 + hzh2]; |
| } |
| } |
| |
| let [first, second, third, fourth, fifth, sixth] = fibs(); |
| console.log(sixth); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| 13 |
| |
| [Done] exited with code=0 in 0.176 seconds |
上面的代码中,fibs 是一个 Generator 函数,原生具有 Iterator 接口。解构赋值会依次从这个接口中获取值。
上面关于fibs函数这部分不是很懂。
3.1.2 默认值
| |
| |
| let [hzh1 = true] = []; |
| console.log("hzh1 = " + hzh1); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| hzh1 = true |
| |
| [Done] exited with code=0 in 0.194 seconds |
| |
| |
| let [hzh2, hzh3 = 'b'] = ['黄子涵是帅哥!']; |
| let [hzh4, hzh5 = 'c'] = ['黄子涵是靓仔!', undefined]; |
| console.log("hzh2 = " + hzh2); |
| console.log("hzh3 = " + hzh3); |
| console.log("hzh4 = " + hzh4); |
| console.log("hzh5 = " + hzh5); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| hzh2 = 黄子涵是帅哥! |
| hzh3 = b |
| hzh4 = 黄子涵是靓仔! |
| hzh5 = c |
| |
| [Done] exited with code=0 in 0.192 seconds |
注意
ES6 内部使用严格相等运算符(===)判断一个位置是否有值。所以,如果一个数组成员不严格等于undefined,默认值是不会生效。
| |
| |
| let [hzh1 = 1] = [undefined]; |
| let [hzh2 = 2] = [null]; |
| console.log("hzh1 = " + hzh1); |
| console.log("hzh2 = " + hzh2); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| hzh1 = 1 |
| hzh2 = null |
| |
| [Done] exited with code=0 in 0.576 seconds |
上面的代码,如果一个数组成员,默认值就不会生效,因为 null 不严格相等 undefined。
如果默认值是一个表达式,那么这个表达式是惰性求值,即只有在用到时才会求值。
| |
| |
| function huangzihan() { |
| console.log('黄子涵'); |
| } |
| |
| let [hzh = huangzihan()] = [1]; |
| [Running] node "e:\HMV\Babel\hzh.js" |
| |
| [Done] exited with code=0 in 0.594 seconds |
上面的代码中,因为 x 能取到值,所以函数 f 根本不会执行。上面的代码其实等价于下面的代码。
| |
| |
| let hzh; |
| if([1][0] === undefined) { |
| hzh = huangzihan(); |
| } else { |
| hzh = [1][0]; |
| } |
| [Running] node "e:\HMV\Babel\tempCodeRunnerFile.js" |
| |
| [Done] exited with code=0 in 0.194 seconds |
默认值可以引用解构赋值的其他变量,但该变量必须已经声明。
| |
| |
| let [hzh1 = 1, hzh2 = hzh1] = []; |
| console.log("hzh1 = " + hzh1); |
| console.log("hzh2 = " + hzh2); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| hzh1 = 1 |
| hzh2 = 1 |
| |
| [Done] exited with code=0 in 0.176 seconds |
| |
| |
| let [hzh3 = 3, hzh4 = hzh3] = [2]; |
| console.log("hzh3 = " + hzh3); |
| console.log("hzh4 = " + hzh4); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| hzh3 = 2 |
| hzh4 = 2 |
| |
| [Done] exited with code=0 in 0.196 seconds |
| |
| |
| let [hzh5 = 5, hzh6 = hzh5] = [1, 2]; |
| console.log("hzh5 = " + hzh5); |
| console.log("hzh6 = " + hzh6); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| hzh5 = 1 |
| hzh6 = 2 |
| |
| [Done] exited with code=0 in 0.179 seconds |
| |
| |
| let [hzh7 = hzh8, hzh8 = 8] = []; |
| console.log("hzh7 = " + hzh7); |
| console.log("hzh8 = " + hzh8); |
| [Running] node "e:\HMV\Babel\tempCodeRunnerFile.js" |
| e:\HMV\Babel\tempCodeRunnerFile.js:3 |
| let [hzh7 = hzh8, hzh8 = 8] = [] |
| ^ |
| |
| ReferenceError: Cannot access 'hzh8' before initialization |
| at Object.<anonymous> (e:\HMV\Babel\tempCodeRunnerFile.js:3:13) |
| at Module._compile (internal/modules/cjs/loader.js:999:30) |
| at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10) |
| at Module.load (internal/modules/cjs/loader.js:863:32) |
| at Function.Module._load (internal/modules/cjs/loader.js:708:14) |
| at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12) |
| at internal/main/run_main_module.js:17:47 |
| |
| [Done] exited with code=1 in 0.23 seconds |
上面最后一个表达式之所以会报错,是因为 hzh7 用到默认值 hzh8 时,hzh8 还没有声明。
3.2 对象的解构赋值
解构不仅可以用于数组,还可以用于对象。
| |
| |
| let { hzh1, hzh2 } = { hzh1: "黄子涵", hzh2: "尤雨溪" }; |
| console.log("hzh1 = " + hzh1); |
| console.log("hzh2 = " + hzh2); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| hzh1 = 黄子涵 |
| hzh2 = 尤雨溪 |
| |
| [Done] exited with code=0 in 0.229 seconds |
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值是由它的位置决定的;而对象的属性没有次序,变量必须与属性同名才能取到正确的值。
| |
| |
| let { hzh2, hzh1 } = { hzh1: "黄子涵", hzh2: "尤雨溪" }; |
| console.log("hzh1 = " + hzh1); |
| console.log("hzh2 = " + hzh2); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| hzh1 = 黄子涵 |
| hzh2 = 尤雨溪 |
| |
| [Done] exited with code=0 in 0.196 seconds |
| |
| |
| let { hzh2 } = { hzh1: "黄子涵", hzh2: "尤雨溪" }; |
| console.log("hzh3 = " + hzh3); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| e:\HMV\Babel\hzh.js:4 |
| console.log("hzh3 = " + hzh3) |
| ^ |
| |
| ReferenceError: hzh3 is not defined |
| at Object.<anonymous> (e:\HMV\Babel\hzh.js:4:25) |
| at Module._compile (internal/modules/cjs/loader.js:999:30) |
| at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10) |
| at Module.load (internal/modules/cjs/loader.js:863:32) |
| at Function.Module._load (internal/modules/cjs/loader.js:708:14) |
| at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12) |
| at internal/main/run_main_module.js:17:47 |
| |
| [Done] exited with code=1 in 0.171 seconds |
上面代码的第一个例子中,等号左边的两个变量的次序与等号右边两个同名属性的次序不一致,但是对取值完全没有影响。第二个例子的变量没有对应的同名属性,导致取不到值,最后等于 undefined 。
如果变量名与属性名不一致,必须写成下面这样
| |
| |
| let { hzh1: hzh3 } = { hzh1: "黄子涵", hzh2: "尤雨溪" }; |
| console.log("hzh3 = " + hzh3); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| hzh3 = 黄子涵 |
| |
| [Done] exited with code=0 in 0.203 seconds |
| |
| |
| let huangzihan = { hzh1: '黄子涵', hzh2: '尤雨溪'}; |
| let { hzh1: h, hzh2: z} = huangzihan; |
| console.log("hzh1对象的h属性:" + h); |
| console.log("hzh2对象的z属性:" + z); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| hzh1对象的h属性:黄子涵 |
| hzh2对象的z属性:尤雨溪 |
| |
| [Done] exited with code=0 in 0.194 seconds |
实际上说明,对象的解构赋值是下面形式的简写。
| |
| |
| let { hzh1: hzh1, hzh2: hzh2} = { hzh1: '黄子涵', hzh2: '尤雨溪'}; |
| console.log("hzh1 = " + hzh1); |
| console.log("hzh2 = " + hzh2); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| hzh1 = 黄子涵 |
| hzh2 = 尤雨溪 |
| |
| [Done] exited with code=0 in 0.2 seconds |
也就是说,对象的解构赋值的内部机制是先找到同名属性,然后再赋值给对应的变量。真正被赋值的是后者,而不是前者。
| |
| |
| let { hzh1: hzh3} = { hzh1: '黄子涵', hzh2: '尤雨溪'}; |
| console.log("hzh3 = " + hzh3); |
| console.log("hzh1 = " + hzh1); |
| [Running] node "e:\HMV\Babel\hzh.js" |
| hzh3 = 黄子涵 |
| e:\HMV\Babel\hzh.js:5 |
| console.log("hzh1 = " + hzh1) |
| ^ |
| |
| ReferenceError: hzh1 is not defined |
| at Object.<anonymous> (e:\HMV\Babel\hzh.js:5:25) |
| at Module._compile (internal/modules/cjs/loader.js:999:30) |
| at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10) |
| at Module.load (internal/modules/cjs/loader.js:863:32) |
| at Function.Module._load (internal/modules/cjs/loader.js:708:14) |
| at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12) |
| at internal/main/run_main_module.js:17:47 |
| |
| [Done] exited with code=1 in 0.176 seconds |
上面的代码中,hzh1是匹配的模式,hzh3才是变量。真正被赋值的是变量 hzh3,而不是模式 hzh1。
与数组一样,解构也可以用于嵌套结构的对象。
注意,这时p是模式,不是变量,因此不会被赋值。如果p也要作为变量赋值,可以写成下面这样。
上面的代码有三次解构赋值,分别是对 loc、start、line 三个属
性的解构赋值。需要注意的是,最后一次对line属性的解构赋值
之中,只有line是变量,loc和start都是模式,不是变量。
下面是嵌套赋值的例子。
3.3 字符串的解构赋值
3.4 数值和布尔值的解构赋值
3.5 函数参数的解构赋值
3.6 圆括号问题
3.6.1 不能使用圆括号的情况
3.6.2 可以使用圆括号的情况
3.7 用途
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?