首先,值的拷貝,一般有三種方式,因爲基本類型與引用類型在內存中存儲位置和存儲方式的不一樣,致使瞭如下三種概念的衍生:javascript
var new_arr = JSON.parse( JSON.stringify(arr) );複製代碼
但此法沒法拷貝函數。concat、slice、JSON.stringify 都算是技巧類,能夠根據實際狀況適當使用。java
在看開源項目的過程當中,常常會看到相似以下的源碼。for...in
循環對象的全部枚舉屬性,而後再使用hasOwnProperty()
方法來忽略繼承屬性。
git
const shallowClone = (obj) => {
if (typeof obj !== 'object') return
let newObj = obj instanceof Array ? [] : {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key]
}
}
return newObj
}複製代碼
const deepClone = (obj) => {
if (typeof obj !== 'object') return
let newObj = obj instanceof Array ? [] : {}
for (let key in obj) {
if (typeof obj[key] === 'object') {
newObj[key] = deepClone(obj[key])
} else {
newObj[key] = obj[key]
}
}
return newObj
}複製代碼
深拷貝會徹底的克隆一個新對象,但由於使用遞歸,性能會不如淺拷貝,在開發中,仍是要根據實際狀況進行選擇。
github
Underscore _.clone()
segmentfault
其實是一種淺複製 (shallow-copy),全部嵌套的對象和數組都是直接複製引用而並無進行深複製。源碼:
數組
// Create a (shallow-cloned) duplicate of an object.
_.clone = function(obj) {
if (!_.isObject(obj)) return obj;
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};複製代碼
var x = {
a: 1,
b: { f: { g: 1 } },
c: [ 1, 2, 3 ]
};
var y = $.extend({}, x), //shallow copy
z = $.extend(true, {}, x); //deep copy
y.b.f === x.b.f // true
z.b.f === x.b.f // false複製代碼
在lodash中關於複製的方法有兩個,分別是_.clone()
和_.cloneDeep()
。其中_.clone(obj, true)
等價於_.cloneDeep(obj)
。
bash
jQuery 沒法正確深複製 JSON 對象之外的對象,而 lodash 花了大量的代碼來實現 ES6 引入的大量新的標準對象。lodash 針對存在環的對象的處理也是很是出色的。所以相較而言,lodash 在深複製上的行爲反饋比前兩個庫好不少。函數
參考源:
post
https://juejin.im/post/59ac1c4ef265da248e75892b
性能
https://segmentfault.com/a/1190000002801042
https://github.com/mqyqingfeng/Blog/issues/32