JavaScript浅拷贝与深拷贝

定义

浅拷贝(shallow copy):只复制指向某个对象的指针,而不复制对象本身,新旧对象共享一块内存。
深拷贝(deep copy):复制并创建一个一摸一样的对象,不共享内存,修改新对象,旧对象保持不变。

示例

1. 基本数据类型


// 基本数据类型

var a = 1;
var b = a;
b = 2;

console.log(a); // 1
console.log(b); // 2
  • 基本数据类型(number、string、boolean,null、undefined)进行赋值时,按值传递。
  • 当 b=a 赋值时,栈内存会新开辟一个内存,所以当修改b时,不会影响a。
变量a在内存中的存储
b=a赋值之后内存的存储

注:基本数据类型,变量名和值都存储在栈内存中。

2. 引用数据类型


// 示例1 -- 数组
var a = [1, 2, 3, 4];
var b = a;

console.log(a === b);
a[0] = 0; // 修改数组a的值
console.log(a);
console.log(b);

// 示例2 -- 对象
var obj = {
    name: 'Lucy',
    age: 17
}
var newObj = obj;
newObj.name = 'Andy'; // 修改新的对象的属性name的值
console.log(obj);
console.log(newObj);
示例1输出结果
示例2输出结果
  • 数组和对象进行赋值操作时,是按引用传值;
  • 当赋值时,复制的仅是指针地址而已;
  • 浅拷贝和深拷贝都只针对于像Object, Array这样的复杂对象;
  • 区别:浅拷贝只复制对象的第一层属性、深拷贝可以对对象的属性进行递归复制。
数组赋值过程

注: 引用数据类型,变量名存在栈内存中,值存在于堆内存中,栈内存提供一个引用的地址指向堆内存中的值。

实现

1. 浅拷贝

① 对数组或对象进行普通的赋值。

var a = [1, 2, 3, 4];
var b = a;

console.log(a === b); // true
a[0] = 0; // 修改数组a的值
console.log(a); // [0, 2, 3, 4]
console.log(b); // [0, 2, 3, 4]

② Object.assign() --- 用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

Object.assign(target, ...sources)
参数:
target -- 目标对象
source -- 源对象
返回值
目标对象

var obj = {
    student: {
        name: 'Lucy',
        age: 17
    }
}

var newObj = Object.assign({}, obj);
newObj.student.name = "Andy";
console.log(obj);
console.log(newObj);
Object.assign() 多层属性时赋值
注:Object.assign() 只能实现非递归属性的一层的深度拷贝。
var obj1 = {
    name: 'Lucy',
    age: 17
};
var obj2 = Object.assign({}, obj1);
obj2.name = 'Andy';
console.log(obj1);
console.log(obj2);
Object.assign()实现一层属性深拷贝

2. 深拷贝

(1)数组

① slice() -- 从已有的数组中返回选定的元素。

arrayObject.slice(start,end)
参数
start -- 数组起始位置,包括此位置,如果负数,从数组尾部算起。
end -- 截取的结束位置,不包括此位置,如果负数,从数组尾部算起,如果省略,默认到结束所有元素。
返回值
新的数组 [start, end)

var arr1 = [1, 2, 3, 4];
var arr2 = arr1.slice(0);
arr2[0] = 0;
console.log(arr1);
console.log(arr2);
slice()实现一层属性深拷贝

② concat() ---- 用于连接两个或多个数组。

arrayObject.concat(arrayX,arrayX,......,arrayX)

参数
arrayX -- 可以为具体的值或数组对象。
返回值
新的数组。


var arr1 = [1, 2, 3, 4];
var arr2 = arr1.concat();
arr2[0] = 0;
console.log(arr1);
console.log(arr2);
concat()实现一层属性深拷贝
var arr1 = [1, [2, 3], 4];
var arr2 = arr1.slice();
arr2[1][0] = [5, 6];
console.log(arr1);
console.log(arr2);
多层属性时
(2)对象

① 手动复制遍历每个属性

var obj1 = {
    name: "Lucy",
    age: 17
};

var obj2 = new Object();
obj2.name = obj1.name;
obj2.age = obj1.age;
obj2.name = "Andy";

console.log(obj1);
console.log(obj2);
手动复制

② Object.assign() -- 仅针对对象只有一层属性,不存在递归属性。
③ 转成JSON

JSON.stringify()把对象转成字符串;JSON.parse() 把字符串转成新的对象。

 var obj1 = {
    student: {
        name: 'Lucy',
        age: 17
    }
}
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.student.name = 'Andy';

console.log(obj1 === obj2);
console.log(obj1);
console.log(obj2);
JSON实现深拷贝

④ 递归

 var obj1 = {
    student: {
        name: 'Lucy',
        age: 17
    }
}

function deepCopy(obj) {
    var result = {};
    for (var name in obj) {
        if (typeof obj[name] === 'object') {
            result[name] = deepCopy(obj[name]);
        } else {
            result[name] = obj[name];
        }
    }
    return result;
}

var obj2 = deepCopy(obj1);
obj2.student.name = 'Andy';

console.log(obj1 === obj2);
console.log(obj1);
console.log(obj2);
递归实现深拷贝

⑤ JQuery的extend()方法 -- 用于将一个或多个对象的内容合并到目标对象。

$.extend( [deep ], target, object1 [, objectN ] )
参数
deep - 是否进行深度拷贝,默认为false
target- Object类型 目标对象,其他对象的成员属性将被附加到该对象上。
object1 - Object类型 第一个被合并的对象
返回值
目标对象

var arr1 = [1, 2, [3, 4], 5];
var arr2 = $.extend(true, [], arr1);
arr1[2][0] = [7, 8];
console.log(arr1);
console.log(arr2);
$.extend()实现深拷贝

在默认情况下,通过$.extend()合并操作不是递归的(浅拷贝);如果第一个对象的属性本身是一个对象或数组,那么它将完全用第二个对象相同的key重写一个属性。这些值不会被合并。然而,如果将 true 作为该函数的第一个参数,那么会在对象上进行递归的合并(深拷贝)。

浅拷贝(false 默认):如果第二个参数对象有的属性第一个参数对象也有,那么不会进行相同参数内部的比较,直接将第一个对象的相同参数覆盖。

深拷贝(true):如果第二个参数对象有的属性第一个参数对象也有,还要继续在这个相同的参数向下一层找,比较相同参数的对象中是否还有不一样的属性,如果有,将其继承到第一个对象,如果没有,则覆盖。

var obj1 = {
    student: {
        name: 'Lucy',
        age: '17',
        gender: 'female'
    },
    grade: 1
}
var obj2 = {
    student: {
        name: 'Andy',
        age: 18,
    },
    grade: 2,
    hobby: 'football'
}

console.log($.extend(obj1, obj2));
extend()浅拷贝
var obj1 = {
    student: {
        name: 'Lucy',
        age: '17',
        gender: 'female'
    },
    grade: 1
}
var obj2 = {
    student: {
        name: 'Andy',
        age: 18,
    },
    grade: 2,
    hobby: 'football'
}

console.log($.extend(true, obj1, obj2));
extend()深拷贝

参考

JS深拷贝与浅拷贝的区别,实现深拷贝的几种方法
JavaScript中浅拷贝和深拷贝的区别和实现
关于JavaScript的浅拷贝和深拷贝
JQuey.extend()的深拷贝和浅拷贝详细讲解

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容