浅拷贝
浅拷贝是处理栈内存。
不同形式的浅拷贝示例:
- 基本类型
如果是基本类型:number、string、boolean、null、undefined,浅拷贝复制的是值。
var a = 1;
var b = a; // 拷贝
b = 2;
console.log('a=',a); // a = 1
- 引用类型
如果是引用类型:object、array,浅拷贝复制的是引用。
var small = {
name: 'jane',
age: 18
};
var big = small; // 拷贝
big.age = 30;
console.log('small=',small); // small= { name: 'jane', age: 30 }
检测数据类型
var isType = function (obj) {
var str = Object.prototype.toString.call(obj);
var type = str.slice(8, str.length - 1);
return type;
}
如果采用=直接赋值的方式拷贝引用类型,浅拷贝复制的是引用,这样会造成目标对象和源对象共用一个对象,改变其中一个,就会对另外一个产生影响。
浅拷贝对象的另一种实现方式(遍历对象,并返回新的对象):
var extend = function (target, source) {
// 检测参数
if (!source || arguments.length !== 2) {
throw new Error("参数错误")
}
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];
// 将源对象中的属性复制到目标对象中
target[property] = copy;
}
// 返回目标对象
return target;
}
测试用例
var target = {},
source = {
name: "jane",
age: 18,
link: [ 1, 2]
};
target = extend(target, source);
target.age = 30; // 修改目标对象中的基础类型,不影响源对象
target.link[0] = 100; // 修改目标对象中的数组,影响源对象
console.log(target); // { name: 'jane', age: 30, link: [ 100, 2 ] }
console.log(source); // { name: 'jane', age: 18, link: [ 100, 2 ] }
对比打印结果,可以发现浅拷贝只能复制一层结构,当存在嵌套时,就捉襟见肘了。
深拷贝
深拷贝不仅处理栈内存,而且处理堆内存。
var deepExtend = function (target, source) {
// 检测参数
if (!source || arguments.length !== 2) {
throw new Error("参数错误")
}
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; }
// 将源对象中的属性复制到目标对象中
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;
}
}
// 返回目标对象
return target;
}
测试用例
var target = {},
source = {
name: "jane",
age: 18,
link: [ 1, 2]
};
target = deepExtend(target, source);
target.age = 30; // 修改目标对象中的基础类型,不影响源对象
target.link[0] = 100; // 修改目标对象中的数组,不影响源对象
console.log(target); // { name: 'jane', age: 30, link: [ 100, 2 ] }
console.log(source); // { name: 'jane', age: 18, link: [ 1, 2 ] }
参考
理解jquery的深拷贝源码
javascript深拷贝--司徒正美
javaScript中的浅拷贝和深拷贝
深入剖析JavaScript的深复制