补充:扩展运算符位置
对象中的扩展运算符(…)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中(数组也一样,自己替换)
- 扩展运算符用作合并时他是放在需要被合并的数组/对象前的。
- 扩展运算符用作表示将还未匹配的数据包起来匹配给某变量时放在该变量前面。
补充:扩展运算符与深、浅拷贝
- 基本数据类型(值类型),比如number,string,boolean,是可以使用扩展运算符进行深拷贝的
- 引用类型的值,比如Object,Array,。引用类型使用扩展运算符进行的是浅拷贝,只是拷贝了引用地址。
解构赋值
解构赋值语法是一个JavaScript表达式,它可以将值从数组或属性从对象中提取到不同的变量中。
–MDN
我认为,解构赋值可以将 值从数组 或 属性从对象 中提取到不同的变量或者常量const中。
举例理解:
对象中,const {name} = obj;
等价于const name = obj.name;
数组与对象的解构赋值相对重要一些,字符串、数值与布尔值、函数的解构赋值建立在数组与对象的解构赋的基础之上。
数组的解构赋值
- 等号两边都是数组结构
let [a,b,c,d]=const[1,2,3,4]
- 左边的
[]
中为需要赋值的变量 - 右边为需要解构的数组
更复杂的匹配规则
默认值
- 在数组的解构赋值中可以使用
=
设置默认值,当解构赋值中匹配到undefined时自动使用默认值。 - const常量没有匹配到默认值时在这并不会报错,会反回undefined。
- 注意:一定是undefined才会使用默认值,null不会。
交换变量
使用数组的解构赋值可以使交换变量更加方便。
接收多个“函数返回值”
使用数组的解构赋值可以使接收多个“函数返回值”更加方便。
注意:return返回的是一个数组,第一项返回的是布尔值,第二项是一个对象,第三项返回字符串。通过数组的解构赋值可以将函数的多个返回值分别获取为status、data、msg。
结合扩展运算符(...
)
- 可用于解构赋值中获取剩余数组元素、复制数组、合并数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 解构赋值中获取剩余数组元素
const arr = [ 1, 2, 3, 4 ]
const [ a, b, ...c ] = arr // c 是 [ 3, 4 ]
//数组合并
const cArr1 = [1, 2, 3, ...arr1];
console.log(cArr1);//[1, 2, 3, 1, 2, 3, 4]
const cArr2 = [...arr1, ...arr2, ...arr3];
console.log(cArr2);// [1, 2, 3, 4, 4, 3, 2, 1, "nihao", 2.2, false]
//复制数组arr3
const cArr3 = [...arr3];
console.log(cArr3);//["nihao", 2.2, false]
const [...cArr4] = arr3;
console.log(cArr4);//["nihao", 2.2, false] - 注意:
- 扩展运算符与数组的解构赋值结合使用时只能放在最后,因为扩展运算符在这的意思是将数组后面剩余的还未匹配的值都包起来赋给使用了扩展运算符的那个变量
- 变量a和b分别取到1和2,扩展运算符使得arr中剩余的3,4都包在一个数组内给了变量c
对象的解构赋值
- 对象的结构赋值与数组的结构赋值相似。
- 等号左右两边都为对象结构
const{a,b}={a:1,b:2}
- 左边的
{}
中为需要赋值的变量(常量) - 右边为需要解构的对象
- 注意:等号左边的变量名必须与等号右边的对象属性完全一致才能匹配到,不一致则会返回undefined。
- 数组的解构赋值之所以不需要左右一样是因为数组是有序的,他可以通过数组下标进行查找。而对象是无序的,所以必须要变量名与属性名一致才能完成查找。
帮助理解:const { saber } = obj;
相当于const saber = obj.saber;
稍微复杂的解构条件
总结:
可以将数组的解构赋值和对象的解构赋值一起使用,只要保证等号两边模式一致就能匹配上。(如何才是保证等号两边模式一致可以看第三个例子)
只想获取skill中的数组第一项而不想获取skill时,可以在对象的解构赋值中使用数组的解构赋值,此时就可以使用skill1,因为数组解构赋值对命名没有要求。(注意:要保证两边模式一致,不要漏掉对象的解构赋值和数组的解构赋值中间的冒号)
- 在对象中使用数组的解构赋值,获取skillNarme属性值注意:等号左右两边要模式一致才能匹配成功!所以不要漏掉大括号、冒号、中括号!
- const不能重复定义,而
{skillName}
的意思是“获取skll中验组第二项的skillName属性值并赋给常量skillName”,所以采用{skillName:sklName}
以免出现两个常量skillName而报错
结合扩展运算符(...
)
获取剩余属性
- 如果只知道对象的部分属性名又想获取剩余的属性时可以使用扩展运算符(其实这里应该叫剩余参数,他们符号相同含义不同)。
- 扩展运算符(
...oth
)在对象的解构赋值中的作用是获取没有匹配到的剩余属性并把它们作为对象包起来返回。
1 | const obj = { a: "lalalla", b: "kkk", c: "hahah"}; |
复制对象
- 使用扩展运算符复制对象是浅拷贝的。
- 也就是说当你复制的对象obj1中包含一个对象c时,你实际上复制的是c的引用,当你修改复制所得到的对象copyObj1中的对象c的aa属性时,被复制的obj1对象中的对象c的属性aa也会被改变。
- 而修改对象copyObj1的第一层属性b时是不会改动到复制对象obj1的属性b的值的:
1 | const obj1 = a: 1, b: 2, c: { aa: 3, bb: 4 }; |
合并对象
- 如果合并的两个对象中都含有相同属性名的属性,则属性顺序还是按照前面对象的,但后面对象的属性值覆盖前面的。(例子如下)
- 不管是使用扩展运算符复制对象还是合并对象,他们都是浅拷贝的。(例子如下)
1 | // 合并对象 |
如何对已经申明了的变量进行对象的解构赋值
首先我们要明确,虽然可以解决这个问题,但还是建议变量的申明与对象解构赋值同时进行。(也就是例子中的第一张图片)
解决方法:使用小括号将这一条解构赋值的语句括起来即可。
例子:
下图变量age是已经申明才进行解构赋值的,此时{}
会被认为是块级作用域而不是对象的解构赋值,想要将对象obj赋给一个块级作用域就报错了。
默认值
和数组的解构赋值的默认值用法一样,使用=
,当属性没有匹配到或者匹配到undefined时就会返回默认值。
对象的解构赋值的主要用途
提取对象属性
在上图中可以看到hobby属性是没有获取到的,我们只获取了name属性以及hobby属性中的数组第一项。
想要获取hobby属性需要在对象的解构赋值中另外加上hobby:
使用对象传入乱序的函数参数
在这个例子中可以看到调用AJAX函数会传入一个对象作为参数,在这里我们使用AJAX函数时传入的参数具有属性url、data,虽然没有type,但是type有默认值,所以最后打印出来的是默认值get。
data和url的顺序可以颠倒,毕竟对象的解构赋值只要属性名一致即可这也就是为什么可以传入乱序的函数参数。
获取多个“函数返回值”
- 在这个例子中,可以发现利用对象的解构赋值来获取多个“函数返回值”的方法和数组时非常相似。
- 需要注意的是变量名与属性名一致才能匹配到,如果你希望获取到的值不是原本的属性名,可以直接在解构赋值时采用
属性名:希望获得的变量名
的写法,比如例子中的msg:message
意思就是获取对象中的msg属性值并赋给变量message。