注册

JavaScript深浅拷贝的实现

前置知识



  • 对象类型在赋值的过程中其实是复制了地址,从而会导致改变了一方其他也都被改变的情况

    let a = {
age: 1
}
let b = a
a.age = 2
console.log(b.age) // 2

浅拷贝



  • Object.assign : 拷贝所有的属性值到新的对象中,如果属性值是对象的话,拷贝的是地址,所以并不是深拷贝

    let a = {
age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age) // 1


  • 通过展开运算符 ... 来实现浅拷贝

    let a = {
age: 1
}
let b = {...a}
a.age = 2
console.log(b.age) // 1

深拷贝



  • JSON.parse(JSON.stringify(object))

    • 会忽略 undefined
    • 会忽略 symbol
    • 不能序列化函数
    • 不能解决循环引用的对象,会报错抛出异常



    let a = {
age: 1,
jobs: {
first: 'FE'
}
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE

let a = {
age: undefined,
sex: Symbol('male'),
jobs: function() {},
name: 'yck'
}
let b = JSON.parse(JSON.stringify(a))
console.log(b) // {name: "yck"}


  • 递归

    function isObject(obj) {
//Object.prototype.toString.call(obj) === '[object Object]'要保留数组形式,用在这里并不合适
return typeof obj === 'object' && obj != null
}

function cloneDeep1(obj){
if(!isObject(obj)) return obj
var newObj = Array.isArray(obj)? [] : {}
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = isObject(obj[key])? cloneDeep1(obj[key]) : obj[key]
}
}
return newObj
}


  • 问题:递归方法最大的问题在于爆栈,当数据的层次很深是就会栈溢出,例如循环引用


var a = {
name: "muyiy",
a1: undefined,
a2: null,
a3: 123,
book: {title: "You Don't Know JS", price: "45"}
}
a.circleRef = a

// TypeError: Converting circular structure to JSON
JSON.parse(JSON.stringify(a))

//Uncaught RangeError: Maximum call stack size exceeded at Object.hasOwnProperty (<anonymous>)
cloneDeep1(a)



  • 解决方法:循环检测(设置一个数组或者哈希表存储已拷贝过的对象,当检测到当前对象已存在于哈希表中时,取出该值并返回即可)

//哈希表
function cloneDeep3(source, hash = new WeakMap()) {

if (!isObject(source)) return source;
if (hash.has(source)) return hash.get(source); // 新增代码,查哈希表

var target = Array.isArray(source) ? [] : {};
hash.set(source, target); // 新增代码,哈希表设值

for(var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
if (isObject(source[key])) {
target[key] = cloneDeep3(source[key], hash); // 新增代码,传入哈希表
} else {
target[key] = source[key];
}
}
}
return target;
}

//数组
function cloneDeep3(source, uniqueList) {

if (!isObject(source)) return source;
if (!uniqueList) uniqueList = []; // 新增代码,初始化数组

var target = Array.isArray(source) ? [] : {};

// 数据已经存在,返回保存的数据
var uniqueData = find(uniqueList, source);
if (uniqueData) {
return uniqueData.target;
};

// 数据不存在,保存源数据,以及对应的引用
uniqueList.push({
source: source,
target: target
});

for(var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
if (isObject(source[key])) {
target[key] = cloneDeep3(source[key], uniqueList); // 新增代码,传入数组
} else {
target[key] = source[key];
}
}
}
return target;
}

// 新增方法,用于查找
function find(arr, item) {
for(var i = 0; i < arr.length; i++) {
if (arr[i].source === item) {
return arr[i];
}
}
return null;
}

链接:https://juejin.cn/post/7010707434473783309

0 个评论

要回复文章请先登录注册