乐趣区

JS每日一题:深拷贝与浅拷贝的区别?如何实现一个深拷贝

20190311 期
深拷贝与浅拷贝的区别?如何实现一个深拷贝
在回答这个问题前,我们先来回顾一下JS中两大数据类型

基本类型 Undefined、Null、Boolean、Number、String
引用类型 Object Array

基本类型
基本类型就是值类型, 存放在栈 (stack) 内存中的简单数据段,数据大小确定,内存空间大小可以分配
引用类型
引用类型, 存放在堆 (heap) 内存中的对象,变量实际保存的是一个指针,这个指针指向另一个位置
根据上面的分析,我们分别是两处类型做一个 copy 处理
let obj = {
name: ‘ 每日一题 ’,
value: ‘JS’
}

let obj2 = obj
let obj3 = obj.name

console.log(obj2.value) //JS
console.log(obj3) // 每日一题

// 改变 obj2,obj3
obj2.value = ‘CSS’
obj3 = ‘HTML’

console.log(obj.value) // CSS
console.log(obj.name) // 每日一题

从上面的输出结束来看,我们可以猜测 obj,obj2 操作的是同一个对象, 而 obj 和 obj3 是完全独立的, 说到这里就进入了深浅拷贝
浅拷贝
概念: 对于字符串类型,浅拷贝是对值的复制,对于对象来说,浅拷贝是对对象地址的复制, 也就是拷贝的结果是两个对象指向同一个地址
基本概念回过头去看上面的代码我们就能分析出来其都是浅复制
深拷贝
概念: 深拷贝开辟一个新的栈,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性
如何实现深拷贝
JSON.stringify()
首先安利一个无脑黑科技骚操作 * 缺点: JSON.stringify()无法正确处理函数
let obj = {
name: ‘ 每日一题 ’,
value: ‘JS’
}
console.log(JSON.parse(JSON.stringify(obj))) // 深拷贝了一份 obj

let obj = {
name: ‘ 每日一题 ’,
value: ‘JS’,
fn: function(){}
}
console.log(JSON.parse(JSON.stringify(obj))) // obj.fn 丢失
递归
讲到深 copy 很多人都会想到 extend 方法, 没错,这玩意 deep 为 true 确实能深 copy,我们就过来翻一翻他的源码
这边以大家熟悉的 jquery 为例
// 源码地址 https://github.com/jquery/jquery/blob/5bdc85b82b84e5459462ddad9002f22d1ce74f21/src/core.js#L125

// 只取核心逻辑代码, 感兴趣的可以自行去源码地址查看具体实现
// 有英文注释,我就不蹩脚翻译了
// 整体思路就是递归对象,判断类型,处理类型
for (; i < length; i++) {

// Only deal with non-null/undefined values
if (( options = arguments[ i] ) != null ) {

// Extend the base object
for (name in options) {
copy = options[name];

// Prevent never-ending loop
if (target === copy) {
continue;
}

// Recurse if we’re merging plain objects or arrays
if (deep && copy && ( jQuery.isPlainObject( copy) ||
(copyIsArray = Array.isArray( copy) ) ) ) {
src = target[name];

// Ensure proper type for the source value
if (copyIsArray && !Array.isArray( src) ) {
clone = [];
} else if (!copyIsArray && !jQuery.isPlainObject( src) ) {
clone = {};
} else {
clone = src;
}
copyIsArray = false;

// Never move original objects, clone them
target[name] = jQuery.extend(deep, clone, copy);

// Don’t bring in undefined values
} else if (copy !== undefined) {
target[name] = copy;
}
}
}
}
总结

浅拷贝是复制, 两个对象指向同一个地址
深拷贝是新开栈, 两个对象指向不同的地址

关于 JS 每日一题
JS 每日一题可以看成是一个语音答题社区 每天利用碎片时间采用 60 秒内的语音形式来完成当天的考题 群主在次日 0 点推送当天的参考答案
注 绝不仅限于完成当天任务,更多是查漏补缺,学习群内其它同学优秀的答题思路
点击加入答题

退出移动版