在做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()方法和擴展運算符進行的是對象的淺度複製。如果遇見的是引用對象類型的鍵值,那麼複製的將是這個值的引用。
關於淺度複製和深度複製的區別以及方法還需要再進行研究,在此就不再進行贅述。
最後的話
每學一個新的知識,都會更加敬畏,更知天之高。希望未來的我更加努力,道心依舊。
上述總結若有不足之處希望能不吝嗇的指出,非常感謝,期待能與您一起討論,一起進步。