關於深拷貝跟淺拷貝的區別,以前看過各類博客、論壇對於這個問題的分析以及文章,總結出了一句很是 「精闢」 的解釋:「淺拷貝只是拷貝對象或者數組一級屬性上的基本類型,深拷貝是對對象以及對象的全部子對象進行拷貝」。(想了一下,仍是不太準確。。。)javascript
先了解下基本數據類型跟引用類型的概念java
基本類型:undefined
,null
,Boolean
,String
,Number
,Symbol
(基本類型:基本類型值在內存中佔據固定大小,保存在棧內存
中(不包含閉包
中的變量))git
引用類型:Object
,Array
,Date
,Function
,RegExp
等(引用類型的值是對象,保存在堆內存
中。而棧內存存儲的是對象的變量標識符以及對象在堆內存中的存儲地址(引用),引用數據類型在棧中存儲了指針,該指針指向堆中該實體的起始地址。當解釋器尋找引用值時,會首先檢索其在棧中的地址,取得地址後從堆中得到實體。)github
slice
let arr = [1,2,3,4,5,6]
let copyArr = arr.slice(0,2)
copyArr[0] = 9
console.log(arr[0]) //1
console.log(copyArr[0])//9
複製代碼
slice能夠實現拷貝,若是是二維數組呢?數組
let arr = [1,[2,3],4,5]
let copyArr = arr.slice(0,2)
copyArr[1][0] = 9
console.log(arr[1][0]) //9
console.log(copyArr[1][0])//9
複製代碼
因此slice是淺拷貝閉包
concat
(方法用於鏈接兩個或多個數組,不會改變原數組)let arr = [1,[2,3],4,5]
let copyArr = arr.concat()
copyArr[1][0] = 9
console.log(arr[1][0]) //9
console.log(copyArr[1][0])//9
複製代碼
concat
也屬於淺拷貝函數
let arr1 = [1,[2,3],4]
let copyArr = [...arr1]
copyArr[1][0] = 9
console.log(arr1[1][0])//9
console.log(copyArr[1][0])//9
複製代碼
擴展運算符也屬於淺拷貝ui
關於對象上的拷貝就不依次上代碼了,得出結論是:this
淺拷貝:Object.assign()
和擴展運算符spa
深拷貝:JSON.parse()
和 JSON.stringify()
、經過遞歸
JSON
方法有哪些缺點Map
、Set、Date、function、undefined等類型會丟失let obj = {
a: 1,
printstr: function() {
console.log(0)
}
}
obj.date = new Date()
obj.reg = new RegExp(/^\d{3}\-\d{3,8}$/)
obj.b = undefined
obj.buffer = new ArrayBuffer(8)
let objCopy = JSON.parse(JSON.stringify(obj))
console.log(obj)
console.log(objCopy)
複製代碼
Set
、Map
、RegExp
、ArrayBuffer
會被轉爲空對象,Function
、undefined
會被忽略
補充:Symbol()也會忽略
const x = {}
const y = {x}
x.y = y // Cycle: x.y.x.y.x.y.x.y.x...
const copy = JSON.parse(JSON.stringify(x)) // throws!
複製代碼
function deepClone(obj) {
function isObject(o) {
return (typeof o === 'object' || typeof o === 'function') && o !== null
}
if (!isObject(obj)) {
throw new Error('非對象')
}
let isArray = Array.isArray(obj)
let newObj = isArray ? [...obj] : { ...obj}
Reflect.ownKeys(newObj).forEach(key => {
newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
})
return newObj
}
複製代碼
非原創,以前保存的一個方法;這裏主要是用isArray
去判斷Array
跟Object
,Reflect.ownKeys
方法獲取對象上全部屬性的key
這個方法實現的只是一個簡單的深拷貝,考慮獲得的狀況比較少,若是項目中涉及到比較複雜的狀況,能夠考慮一些比較成熟的庫,好比lodash
、Underscore
等;這些庫對於Symbols
、原型鏈上面的屬性拷貝以及循環引用都有考慮到
參考文章
由於深拷貝中涉及到類型的判斷,這裏總結了下js
中數據類型的類型判斷
typeof
和instanceof
typeof
:這個方法能夠看做是一個js
的bug,該方法不能區分數組、對象、正則、Date等類型,還有一個比較特殊的:Null,typeof null
返回的也是object
instanceof
:用於判斷一個變量是否屬於某個對象的實例,會依次從原型鏈上面去查找
let b = new Array()
alert(b instanceof Array) // true
alert(b instanceof Object) // true
// instanceof的檢測類型必須是對象
let num = 1
num instanceof Number // false
num = new Number(1)
num instanceof Number // true
複製代碼
Array
、Date
、RegExp
、Function
等數據類型的原型鏈上層都是Object
得出結論:上述兩個方法都不能準確的判斷數據類型
consstructor
constructor是原型對象上的一個屬性,默認指向這個原型的構造函數
let arr = [1]
let object = {}
let fun = function() {}
let set = new Set()
let date = new Date()
console.log(arr.constructor)
console.log(object.constructor)
console.log(fun.constructor)
console.log(set.constructor)
console.log(date.constructor)
複製代碼
從上面的代碼能夠看出constructor
能夠判斷引用類型的數據類型,但這個方法也有一些缺點:
(1)undefined和null是不可以判斷出類型的
(2)constructor屬性是能夠被修改的,可能會致使判斷不許確
Object.prototype.toString
toString
是Object原型上面的一個方法,該方法默認返回其調用者的具體類型,更嚴格的講,是toString
運行時this指向的對象類型, 返回的類型
console.log(Object.prototype.toString.call("jerry"))//[object String]
console.log(Object.prototype.toString.call(12))//[object Number]
console.log(Object.prototype.toString.call(true))//[object Boolean]
console.log(Object.prototype.toString.call(undefined))//[object Undefined]
console.log(Object.prototype.toString.call(null))//[object Null]
console.log(Object.prototype.toString.call({name: "jerry"}))//[object Object]
console.log(Object.prototype.toString.call(function(){}))//[object Function]
console.log(Object.prototype.toString.call([]))//[object Array]
console.log(Object.prototype.toString.call(new Date))//[object Date]
console.log(Object.prototype.toString.call(/\d/))//[object RegExp]
function Person(){}
console.log(Object.prototype.toString.call(new Person))//[object Object]
複製代碼
這個方法能夠準確的判斷js
中任意數據的類型
才疏學淺,寫的比較簡單,喜歡的記得點個贊哦~~
文中有哪些沒有涉及到的,歡迎補充~~