在读到这篇文章前,对浅复制的理解存在误区-。- js 深拷贝 vs 浅拷贝
var obj1 = {
name:'Richard',
location:'Beijing',
arr:['1','2','3'],
arr2:['1',['2','3'],['4','5']]
}
var obj2 = obj1;
var shallowCopy = function (obj) {
var copy = {}
for (var prop in obj){
if (obj.hasOwnProperty(prop)){
copy[prop] = obj[prop]
}
}
return copy
}
var obj3 = shallowCopy(obj1);
// 现在改变obj1的name属性
obj1.name = '八哥';
console.log(obj2.name)//八哥
console.log(obj3.name)//Richard
//现在改变obj1的arr属性
obj1.arr = ['一','二','三']
console.log(obj2.arr);//['一','二','三']
console.log(obj3.arr);//['1','2','3']
//现在改变obj1的arr2[1],arr2[2]属性
obj1.arr2[1] = ['二','三']
obj1.arr2[2] = ['四','五']
console.log(obj3.arr2)//['1',['二','三'],['四','五']]
类型 | 和原对象是否指向同一对象 | 第一层数据为基本类型 | 原数据包含子对象 |
---|---|---|---|
赋值 | 是 | 改变会使原数据一同改变 | 改变会使原数据一同改变 |
浅拷贝 | 否 | 改变不会使原数据一同改变 | 改变会使原数据一同改变 |
深拷贝 | 否 | 改变不会使原数据一同改变 | 改变不会使原数据一同改变 |
以下是Zepto的浅复制源码
// 内部方法:用户合并一个或多个对象到第一个对象
// 参数:
// target 目标对象 对象都合并到target里
// source 合并对象
// deep 是否执行深度合并
function extend(target, source, deep) {
for (key in source)
if (deep && (isPlainObject(source[key]) || isArray(source[key]))) {
// source[key] 是对象,而 target[key] 不是对象, 则 target[key] = {} 初始化一下,否则递归会出错的
if (isPlainObject(source[key]) && !isPlainObject(target[key]))
target[key] = {}
// source[key] 是数组,而 target[key] 不是数组,则 target[key] = [] 初始化一下,否则递归会出错的
if (isArray(source[key]) && !isArray(target[key]))
target[key] = []
// 执行递归
extend(target[key], source[key], deep)
}
// 不满足以上条件,说明 source[key] 是一般的值类型,直接赋值给 target 就是了
else if (source[key] !== undefined) target[key] = source[key]
}
// Copy all but undefined properties from one or more
// objects to the `target` object.
$.extend = function(target){
var deep, args = slice.call(arguments, 1);
//第一个参数为boolean值时,表示是否深度合并
if (typeof target == 'boolean') {
deep = target;
//target取第二个参数
target = args.shift()
}
// 遍历后面的参数,都合并到target上
args.forEach(function(arg){ extend(target, arg, deep) })
return target
}
/**
* 数组的深拷贝实现
* @param {Array} src
* @param {Array} target
**/
function cloneArr(src,target) {
for (let item of src){
if (Array.isArray(item)){
target.push(cloneArr(item,[])); //新建一个空数组存放深复制的值
}else if (typeof item === 'object'){
target.push(deepCopy(item,{}));
}else {
target.push(item)
}
}
return target;
}
/**
* 对象的深拷贝实现
*@param {Object} src
*@param {Object} target
*@return {Object}
**/
function deepCopy(src,target) {
const keys = Reflect.ownKeys(src);
//返回一个对象属性名的字符数组: [key1,key2,...]
let value = null;
for (let key of keys){ //ES6 创建一个循环迭代可迭代的对象
value = src[key]
if (Array.isArray(value)){
target[key] = cloneArr(value,[]);
}else if (typeof value === 'object'){
target[key] = deepCopy(value,{});
}else {
target[key] = value
}
}
return target;
}
var a = {
name:'八哥',
arr:[1,[2,3],[4,5]],
obj:{x:1,y:2}
}
var b = {}
deepCopy(a,b)
//以下为测试
a.arr[1] = [9,10];
console.log(b.arr[1]) //[2,3]
a.obj.x = 100;
console.log(b.obj.x) //1