ES6的擴展運算符可以說是非常好用的,在給多參數函數傳參,替代Apply,合併數組,和解構配合進行賦值方面提供了很好的便利性。
擴展運算符就是三個點“…”,就是將實現了Iterator 接口的對象中的每個元素都一個個的迭代並取出來變成單獨的被使用。
數組中的擴展運算符
- 數組的複製
let arr1 = [1,2,3]
let arr2 = [...arr1]
console.log(arr2)
- 類數組轉數組:
<script type="text/javascript">
let lis = document.getElementsByTagName("li")
// console.log(lis) //HTMLCollection(4) [ li, li, li, li ]
let arr = [...lis]
console.log(arr,Array.isArray(arr)) //Array [] true
</script>
<body>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</body>
- 字符串轉數組
方法一:split
let str ="hello world"
let arr = str.split("")
console.log(arr) //[ 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' ]
方法二:…spread
let str ="hello world"
let arr = [...str]
console.log(arr,Array.isArray(arr)) //[ 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' ] true
- 合併數組
方法一:concat
let arr1 = [1,2]
let arr2 = [3,4]
let arr = arr1.concat(arr2)
console.log(arr,Array.isArray(arr)) //[ 1, 2, 3, 4 ] true
方法二:…spread
let arr1 = [1,2]
let arr2 = [3,4]
let arr = [...arr1,...arr2]
console.log(arr,Array.isArray(arr)) //[ 1, 2, 3, 4 ] true
對象中的擴展運算符
基本原理:
基本數據類型(array)一般存在於棧區;引用數據類型(object)存在於堆區,而每個堆區都有一個相應的標識,存在於棧區。
如果是基本數據類型,…運算時,相當於將棧區的數據複製一份,賦予一個新的arr
如果是引用數據類型,…運算時,相當於將堆區的數據對應的存放在棧區的標識複製一份,然後通過各自的標識去獲取堆區存放的數據。
判斷是深拷貝還是淺拷貝的依據是:判斷數組和對象展開前後是否還存在聯繫
- 展開運算符 展開基本數據類型時是深copy
let arr1 = [1,2,3]
let arr2 = [...arr1]
arr1[0] = 666;
console.log(arr1) // [ 666, 2, 3 ]
console.log(arr2) // [ 1, 2, 3 ]
console.log(arr1 === arr2) // false
- 如果數組中是基本數據類型,slice深copy
let arr = [1,2,3]
let newArr = arr.slice(0)
newArr[0] = 666;
console.log(arr) //[ 1, 2, 3 ]
console.log(newArr) //[ 666, 2, 3 ]
- 如果數組中是引用數據類型,slice淺copy
let obj = {name:"wangcai"}
let arr = [obj,2,3]
let newArr = arr.slice(0)
console.log(arr) //[ { name: 'wangcai' }, 2, 3 ]
console.log(newArr) //[ { name: 'wangcai' }, 2, 3 ]
newArr[0].name = "xiaoqiang";
console.log(arr) //[ { name: 'xiaoqiang' }, 2, 3 ]
console.log(newArr) //[ { name: 'xiaoqiang' }, 2, 3 ]
- 展開對象 對象就一層是深copy
let obj = {name:"wangcai",age:100}
let newObj = {...obj}
console.log(obj) //{ name: 'wangcai', age: 100 }
console.log(newObj) //{ name: 'wangcai', age: 100 }
newObj.name = "xiaoqiang"
console.log(obj) //{ name: 'wangcai', age: 100 }
console.log(newObj) //{ name: 'xiaoqiang', age: 100 }
- 展開對象 對象有多層是淺copy
let obj = {name:"wangcai",age:{number:100}}
let newObj = {...obj}
console.log(obj) //{ name: 'wangcai', age: { number: 666 } }
console.log(newObj) //{ name: 'wangcai', age: { number: 666 } }
newObj.age.number = 666
console.log(obj) //{ name: 'wangcai', age: { number: 666 } }
console.log(newObj) //{ name: 'wangcai', age: { number: 666 } }
當對象有多層時,第二層的對象不會全部存在於堆區,而是隻存放鍵,當棧區通過對應的標識找到堆區中的鍵時,再去根據鍵尋找相應的值 。
實現多層對象的深copy:
- 實現多層對象的深copy
let obj = {name:"wangcai",age:{number:100}}
let newObj = {...obj,age:{...obj.age}}
newObj.age.number = 666
console.log(obj) // { name: 'wangcai', age: { number: 100 } }
console.log(newObj) // { name: 'wangcai', age: { number: 666 } }
- JSON.parse(JSON.stringify(obj))可以實現深copy:該方法只能copy滿足JSON數據格式的數據。我們需要將對象先轉化成字符串 在把字符串轉換成對象
let obj = {name:"wangcai",age:{number:100}}
let str = JSON.stringify(obj)
console.log(str) //{"name":"wangcai","age":{"number":100}}
let newObj = JSON.parse(str)
console.log(newObj) //{ name: 'wangcai', age: { number: 100 } }
obj.age.number = 1000000;
console.log(obj) //{ name: 'wangcai', age: { number: 1000000 } }
console.log(newObj) //{ name: 'wangcai', age: { number: 100 } }
- JSON.parse() 方法將數據轉換爲 JavaScript 對象。
- JSON.stringify() 方法將 JavaScript 對象轉換爲字符串。
自己實現一個深copy
-
基礎版的深copy
-
循環引用時報錯
RangeError: Maximum call stack size exceeded
-
最終版的實現: