浅谈JavaScript深拷贝

前言 JavaScript的浅拷贝、深拷贝是一个老生常谈的话题,真正完美的深拷贝其实是比较困难的,但相对的能应用的场景也同样比较少,个人感觉浅拷贝和深拷贝的核心概念无非是对JavaScript引用类型的理解,普通的值类型可以直接复制,应用类型的直接复制则是对其地址的复制,这个其实就是C语言中的指针的概念。明白了这些深浅拷贝就不难理解了,接下来分享一些常用的操作。 浅拷贝 浅拷贝就是不考虑引用类型,我们把对象的属性或是数组的元素都当作原始类型来看待。 Object.assign() 这个方法是用来合并两个对象的属性,将要拷贝的对象和一个空对象合并就能成为一个新的对象 cosnt temp = { a: 1, b: 2} cosnt obj = Object.assign({}, temp) temp === obj // false es6扩展运算符 ... cosnt temp = { a: 1, b: 2} cosnt obj = { ...temp } 这种方法可以将temp里的属性提取出来放到新的对象里面 const array = [1,2,3,4,5] cosnt newArray = [...array] 数组也是同理 深拷贝 深拷贝要比浅拷贝难实现的多,浅拷贝的方式会把引用类型的地址直接复制过去,不同的两个对象里面的引用类型的属性会互相影响,这种有时候不会符合我们的要求,此时就需要深拷贝。 JSON.parse(JSON.stringify()) 这种配合使用算是比较常用的一种深拷贝方式了,将对象转成字符串,再重新生成对象,这样新生成的对象的引用类型和原对象里面的就不同了。 cosnt temp = { a: 1, b: 2, c: { d: 1 } } cosnt obj = JSON.parse(JSON.stringif(temp)) temp === obj // false temp.c === obj.c // false 这种方式的缺陷是undefined, 函数和对象内部循环引用的属性无法拷贝 MessageChannel MessageChannel的介绍可以查看MDN,这个API其实是建立一个消息管道来进行页面通信使用的,使用这个API的比JSON的方法的优势在于可以进行有循环引用对象的拷贝,但是依然无法拷贝函数 function deepClone(obj) { return new Promise(resolve => { const { port1, port2 } = new MessageChannel() port2.onmessage = event => { return resolve(event.data) } port1.postMessage(obj) }) } const temp = { a: 1, b: 2, c: { d: 1 } } deepClone(temp).then(obj => { console.log(obj) }) _.cloneDeep(value) _.cloneDeep()是lodash库所提供的深拷贝函数,也是个人比较推荐的一种,基本可以满足深拷贝的要求,不需要我们再自己写工具类。 自定义工具类deeepClone 最后当然得自己实现一个,但是一个完美的深拷贝函数要考虑的东西太多了,比如要不要考虑原型链上的属性、Dom对象如何处理、函数如何处理等,所以我提供了一个不太完善的深拷贝函数,这个函数对于对象方法属性的深拷贝也是想了比较久才写出来的。 function deepClone(obj, parent) { function isObj(obj) { return (typeof obj === 'object' || typeof obj === 'function') && obj !== null } function isFunction(obj) { return typeof obj === 'function' } if(!isObj(obj)) { return obj } if(isFunction(obj)) { return obj.bind(parent) } const newObj = Array.isArray(obj) ? [...obj] : {...obj} Reflect.ownKeys(obj).forEach(key => { newObj[key] = isObj(newObj[key]) ? deepClone(newObj[key], newObj) : newObj[key] }) return newObj } let temp = { a: 123, b: { c: function () {return 3} } } let obj = deepClone(temp) 结语 每写一篇文章感觉都是对知识的总结提炼,虽然没人看也要坚持下去。 如果有疏漏的地方,欢迎指出

本文章由javascript技术分享原创和收集

发表评论 (审核通过后显示评论):