淺拷貝
淺拷貝是處理棧內(nèi)存。
不同形式的淺拷貝示例:
- 基本類型
如果是基本類型:number、string、boolean、null、undefined,淺拷貝復(fù)制的是值。
var a = 1;
var b = a; // 拷貝
b = 2;
console.log('a=',a); // a = 1
- 引用類型
如果是引用類型:object、array,淺拷貝復(fù)制的是引用。
var small = {
name: 'jane',
age: 18
};
var big = small; // 拷貝
big.age = 30;
console.log('small=',small); // small= { name: 'jane', age: 30 }
檢測數(shù)據(jù)類型
var isType = function (obj) {
var str = Object.prototype.toString.call(obj);
var type = str.slice(8, str.length - 1);
return type;
}
如果采用=直接賦值的方式拷貝引用類型,淺拷貝復(fù)制的是引用,這樣會造成目標(biāo)對象和源對象共用一個對象,改變其中一個,就會對另外一個產(chǎn)生影響。
淺拷貝對象的另一種實現(xiàn)方式(遍歷對象,并返回新的對象):
var extend = function (target, source) {
// 檢測參數(shù)
if (!source || arguments.length !== 2) {
throw new Error("參數(shù)錯誤")
}
var sourceType = isType(source),
targetType = isType(target);
// 基本類型
if(targetType !== "Object" && targetType !== "Array" && targetType !== "Function") {
target = {};
}
if(sourceType !== "Object" && sourceType !== "Array" && sourceType !== "Function") {
return target = {};
}
// 遍歷源對象中的屬性
for (var property in source) {
var copy = source[property];
// 將源對象中的屬性復(fù)制到目標(biāo)對象中
target[property] = copy;
}
// 返回目標(biāo)對象
return target;
}
測試用例
var target = {},
source = {
name: "jane",
age: 18,
link: [ 1, 2]
};
target = extend(target, source);
target.age = 30; // 修改目標(biāo)對象中的基礎(chǔ)類型,不影響源對象
target.link[0] = 100; // 修改目標(biāo)對象中的數(shù)組,影響源對象
console.log(target); // { name: 'jane', age: 30, link: [ 100, 2 ] }
console.log(source); // { name: 'jane', age: 18, link: [ 100, 2 ] }
對比打印結(jié)果,可以發(fā)現(xiàn)淺拷貝只能復(fù)制一層結(jié)構(gòu),當(dāng)存在嵌套時,就捉襟見肘了。
深拷貝
深拷貝不僅處理棧內(nèi)存,而且處理堆內(nèi)存。
var deepExtend = function (target, source) {
// 檢測參數(shù)
if (!source || arguments.length !== 2) {
throw new Error("參數(shù)錯誤")
}
var sourceType = isType(source),
targetType = isType(target);
// 基本類型
if(targetType !== "Object" && targetType !== "Array" && targetType !== "Function") {
target = {};
}
if(sourceType !== "Object" && sourceType !== "Array" && sourceType !== "Function") {
return target = {};
}
// 遍歷源對象中的屬性
for (var property in source) {
var copy = source[property];
if (source === copy) { continue; }
// 將源對象中的屬性復(fù)制到目標(biāo)對象中
if (isType(copy) === "Object") {
// 遞歸
target[property] = arguments.callee(target[property] || {}, copy);
} else if (isType(copy) === "Array") {
// 遞歸
target[property] = arguments.callee(target[property] || [], copy);
} else {
target[property] = copy;
}
}
// 返回目標(biāo)對象
return target;
}
測試用例
var target = {},
source = {
name: "jane",
age: 18,
link: [ 1, 2]
};
target = deepExtend(target, source);
target.age = 30; // 修改目標(biāo)對象中的基礎(chǔ)類型,不影響源對象
target.link[0] = 100; // 修改目標(biāo)對象中的數(shù)組,不影響源對象
console.log(target); // { name: 'jane', age: 30, link: [ 100, 2 ] }
console.log(source); // { name: 'jane', age: 18, link: [ 1, 2 ] }
參考
理解jquery的深拷貝源碼
javascript深拷貝--司徒正美
javaScript中的淺拷貝和深拷貝
深入剖析JavaScript的深復(fù)制