1、深淺拷貝
我們瞭解到對象(引用)類型在賦值的過程中其實是複製了地址,從而會導致改變了一方其他也都被改變的情況。通常在開發中我們不希望出現這樣的問題。
let a = {
age: 1
}
let b = a
a.age = 2
console.log(b.age) // 2 希望是1
let a = {
name: 'xxx',
obj: {
aa: 3
}
}
let b = a
a.obj.aa = 5
console.log(b.obj.aa) // 5 希望是3
1)淺拷貝
如果我們要複製對象的所有屬性都不是引用類型時,就可以使用淺拷貝,實現方式就是遍歷並複製,最後返回新的對象。
function shallowCopy(obj) {
var copy = {};
// 只複製可遍歷的屬性
for (key in obj) {
// 只複製本身擁有的屬性
if (obj.hasOwnProperty(key)) {
copy[key] = obj[key];
}
}
return copy;
}
let a = {
age: 1
}
let b = shallowCopy(a)
a.age = 2
console.log(b.age) // 1
JS內部實現了淺拷貝,如Object.assign(target, source)
,其中第一個參數是我們最終複製的目標對象,後面的所有參數是我們的即將複製的源對象,支持對象或數組,一般調用的方式爲
var newObj = Object.assign({}, originObj);
2)深拷貝
其實深拷貝可以拆分成 2 步,淺拷貝 + 遞歸,淺拷貝時判斷屬性值是否是對象,如果是對象就進行遞歸操作,兩個一結合就實現了深拷貝。
1、簡單實現
function cloneDeep(source) {
var target = {};
for(var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
if (typeof source[key] === 'object') { //問題一 typeof null === 'object' 傳入null 會返回{} 應該返回 null
// 問題二 數組會轉成對象 [1,2] 會變成 {0: 1, 1: 2}
target[key] = cloneDeep(source[key]); // 注意這裏
} else {
target[key] = source[key];
}
}
}
return target;
}
let a = {
name: 'xxx',
obj: {
aa: 3
}
}
let b = cloneDeep(a)
a.obj.aa = 5
console.log(b.obj.aa) // 3
一個簡單的深拷貝就完成了,但是這個實現還存在很多問題。
-
1、因爲
typeof null === 'object'
,傳入null
時應該返回null
而不是{}
-
2、沒有考慮數組的兼容, 傳入 [1,2 ]時 應該返回 [1,2] 而不是 {0:1, 1:2}
2、:解決以上兩個問題
function cloneDeep2(source) {
if (!isObject(source)) return source; // 非對象返回自身
// if(source === null) return null
//解決數組兼容
var target = Array.isArray(source) ? [] : {};
for(var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
if (isObject(source[key])) {
target[key] = cloneDeep2(source[key]); // 注意這裏
} else {
target[key] = source[key];
}
}
}
return target;
}
// 解決typeof null === 'object'
function isObject(obj) {
return typeof obj === 'object' && obj != null;
}
3、
function deepClone(source) { //遞歸拷貝
if(source === null) return null; //null 的情況
if(source instanceof RegExp) return new RegExp(source);
if(source instanceof Date) return new Date(source);
if(typeof source !== 'object') {
//如果不是複雜數據類型,直接返回
return source;
}
//解決數組兼容
var target = Array.isArray(source) ? [] : {};
for(let key in source) {
//如果 source[key] 是複雜數據類型,遞歸
target[key] = deepClone(source[key]);
}
return target;
}
。。。