在做React Native项目时遇见了扩展运算符,于是将ES新特性中相关的部分学习了一下,在这里作出总结。
目前所遇见的扩展运算符有两种:
1: 数组的扩展运算符
2: 对象的扩展运算符
一:数组的扩展运算符
在数组前面增加...
可以将一个数组转换成用逗号分隔开的参数列表,这在传参时是非常便利
console.log(0, ...[1,2,3], 4) // 输出0 1 2 3 4
1:在函数调用时使用扩展运算符
function add(x, y){
console.log(x + y);
}
var arr = [1, 2];
add(...arr) // 输出3
2:扩展运算符后面还可以使用表达式
const flag = true;
const arr1 = [
...(flag ? [1,2,3,4] : []), 5
];
console.log(arr1) // 输出[1,2,3,4,5]
3:扩展运算符代替apply方法
说到apply方法,也要说起call方法,两个方法的作用是一样的,但是传入的参数不一样,在这里描述的是扩展运算符,因此只解释apply方法。
var arr2 = ['a', 'b'];
var arr3 = [0, 1, 2];
arr2.push.apply(arr2, arr3);
console.log(arr2); // 输出['a','b','c',0,1,2]
apply方法是function对象的原型方法,Function.prototype.apply()
他可以将特定的函数的当作一个方法绑定到指定的对象上进行调用。在这个例子中由于push的参数不能是一个数组,只能通过apply的方式进行变通。将push方法绑定到arr2对象上进行调用。在ES5中通常使用apply将数组转换为函数的参数。在ES6中由于出现了数组的扩展运算符,因此更加简便。
4:使用扩展运算符合并数组
var arr4 = [1,2];
var arr5 = [3,4];
var arr6 = [5,6];
var arr7 = [...arr4, ...arr5, ...arr6]
console.log(arr7) // 输出【1,2,3,4,5,6】
5:扩展运算符可以将字符串转换成真正的数组
var str1 = 'Love';
function getLength(str1){
console.log([...str1].length)
}
getLength(str1) // 输出4
6:注意如果将扩展运算符用于数组赋值,必须要放在数组的最后一位,
二:对象的扩展运算符
ES2017中将扩展运算符进一步引入到了对象中。
1: 复制可遍历属性,以及覆盖扩展对象中的属性
在项目中有如下实例:
// 第一部分:输入框input组件
<Input
placeholder="请输入邮箱"
onChangeText={value => this.handleInputChange('email', value)}
/>
<Input
placeholder="请输入密码"
onChangeText={value => this.handleInputChange('password', value)}
/>
// 第二部分:handleInputChange函数
handleInputChange = (field, value) => {
const newState = {
...this.state,
[field]: value
}
this.setState(newState)
}
// 第三部分: 构造函数中定义state对象
constructor (props) {
super(props)
this.state = {
email: '',
password: ''
}
}
解释:
当输入框中的输入值变化后触发handleInputChange函数,handleInputChange函数中定义了一个newState对象,在对象内部使用扩展运算符将原始state对象进行扩展,在之后[field]: value
进行覆盖。扩展运算符可以取出参数对象的所有可遍历属性并将其复制到当前对象中;如果用户自定义的属性放在扩展运算符的后面,那么扩展运算符内部的同名属性会被覆盖。
2:将自定义属性放在扩展运算符前面则为设置新对象的默认属性值
和前文中的例子不同,在这里是放在扩展运算符的前面;两者相比较的学习更加容易一些。
3:对象的扩展运算符后面可以带有表达式
const flag = false;
const obj = {
...(flag ? {a: 1} : {a: 2}), b: 2
};
console.log(obj) // 输出{ a: 2, b: 2 }
4: 扩展运算符可以用于合并两个对象
const a = { x: 1}
const b = { y: 2}
const c = { ...a, ...b}
console.log(c) // 输出 {x: 1, y: 2}
5:使用扩展运算符进行浅复制
关于对象的复制,一直以来都是一个值得关注的问题。
经过总结,分为两类,一类是键值是复合类型的,另一类是简单类型的数据。
在使用扩展运算符之前通常使用Object.assign()方法进行对象的复制
例子1:只含简单数据类型对象的复制
const obj1 = {a: 1};
const obj2 = {};
Object.assign(obj2, obj1);
console.log(obj2); // 输出{ a: 1 }
obj2.a = 2;
console.log(obj2) // 输出 { a: 2 }
console.log(obj1) // 输出 { a: 1 }
例子2: 含有引用对象类型的复制
const obj1 = {a: [1,2,3]};
const obj2 = {};
Object.assign(obj2, obj1);
console.log(obj2); // 输出 { a: [ 1, 2, 3 ] }
obj2.a[0] = 2;
console.log(obj2); // 输出 { a: [ 2, 2, 3 ] }
console.log(obj1); // 输出 { a: [ 2, 2, 3 ] }
例子3: 使用扩展运算符复制引用对象
const obj1 = {a: [1,2,3]};
const obj2 = {...obj1};
console.log(obj2); // 输出 { a: [ 1, 2, 3 ] }
obj2.a[0] = 2;
console.log(obj2); // 输出 { a: [ 2, 2, 3 ] }
console.log(obj1); // 输出 { a: [ 2, 2, 3 ] }
在之前学习ES6的解构赋值时了解到:在解构赋值中如果遇到的键所对应的值是复合类型的,那么他解构赋值复制的是这个值的引用。
综上,使用Object.assign()方法和扩展运算符进行的是对象的浅度复制。如果遇见的是引用对象类型的键值,那么复制的将是这个值的引用。
关于浅度复制和深度复制的区别以及方法还需要再进行研究,在此就不再进行赘述。
最后的话
每学一个新的知识,都会更加敬畏,更知天之高。希望未来的我更加努力,道心依旧。
上述总结若有不足之处希望能不吝啬的指出,非常感谢,期待能与您一起讨论,一起进步。