快捷搜索:  汽车  科技

js深拷贝与浅拷贝的实现方式(JS之实现深度拷贝)

js深拷贝与浅拷贝的实现方式(JS之实现深度拷贝)for (prop in origin) { if (origin.hasOwnProperty(prop)) { } } // hasOwnProperty()方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(过滤对象原型中的属性 不加其实也可以,但是严谨点还是加上比较好) 判断是否为引用类型let target = {} 使用 for...in 循环遍历数组或对象中的属性ps:手机端代码格式会崩掉,所以代码片段下放一个截图。。封装一个方法,确定需要传入的参数,既然我们是拷贝对象(引用类型),那么我们肯定需要一个参数来接收要拷贝的那个对象。 function deepClone(origin) { } // origin 参数传入要拷贝的对象 准备一个空对象,来接收正在拷贝的那个对象

实现思路

1,判断是否为简单数据类型

2,如果为引用类型,判断是数组还是对象

3,建立相应的数组或对象

4,使用递归深入克隆其内部的引用类型

ps:手机端代码格式会崩掉,所以代码片段下放一个截图。。

第一步,判断是否为原始数据类型

封装一个方法,确定需要传入的参数,既然我们是拷贝对象(引用类型),那么我们肯定需要一个参数来接收要拷贝的那个对象。

function deepClone(origin) { } // origin 参数传入要拷贝的对象

js深拷贝与浅拷贝的实现方式(JS之实现深度拷贝)(1)

准备一个空对象,来接收正在拷贝的那个对象

let target = {}

js深拷贝与浅拷贝的实现方式(JS之实现深度拷贝)(2)

使用 for...in 循环遍历数组或对象中的属性

for (prop in origin) { if (origin.hasOwnProperty(prop)) { } } // hasOwnProperty()方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(过滤对象原型中的属性 不加其实也可以,但是严谨点还是加上比较好)

js深拷贝与浅拷贝的实现方式(JS之实现深度拷贝)(3)

判断是否为引用类型

if (typeof(origin[prop]) == 'object') { console.log('引用类型') } else { console.log('原始数据类型') }

js深拷贝与浅拷贝的实现方式(JS之实现深度拷贝)(4)

ps:此处有个小坑,那就是用 typeof() 判断 null 的时候会打印出 object 所以我们需要在刚才那个地方加上一层判断:

if (origin[prop] !== null && typeof(origin[prop]) == 'object') { console.log('引用类型') } else { console.log('原始数据类型') }

js深拷贝与浅拷贝的实现方式(JS之实现深度拷贝)(5)

正在遍历的这个元素不是null 并且使用typeof()判断打印的是 object,这时候它才是引用类型,嗯~,应该是这样没错啦。

如果为原始数据类型直接赋值完事

if (origin[prop] !== null && typeof(origin[prop]) == 'object') { console.log('引用类型') } else { console.log('原始数据类型') target[prop] = origin[prop] }

js深拷贝与浅拷贝的实现方式(JS之实现深度拷贝)(6)

判断引用类型是数组还是对象

整理判断引用类型需要的数据

前提知识:

Object.prototype.toString.call(['数组']) 会打印出:[object Array]

Object.prototype.toString.call({ name: '对象' }) 会打印:[object Object]

我们用此方法来判断引用类型是数组还是对象。

根据引用类型判断结果,建立相应的数组或对象

如果此引用类型得到的结果是数组类型的,则我们建立一个空数组,如果是对象类型,建立一个空对象。为最后的递归做准备!

if (toStr.call(origin[prop]) === '[object Array]') { target[prop] = [] } else { target[prop] = {} }

js深拷贝与浅拷贝的实现方式(JS之实现深度拷贝)(7)

ps:变量toStr 意指 Object.prototype.toString ,toStr.call(origin[prop])则是Object.prototype.toString.call(对象或数组) 我们使用它打印的结果和 [object Array] 对比,来判断它是数组还是对象,从而执行对象的操作。

使用递归,来遍历正在拷贝的对象其内部的引用类型

由于我们之前已经根据正在拷贝对象的属性名建立起了同名的响应的空数组或空对象,现在我们在它下面执行 deepClone() 将当前判断的引用类型作为参数传入进去,它就会执行我们之前的步骤 deepClone(origin[prop]) 直到是原始数据类型才会从递归中解放出来。

嗯~~~~~,想法虽然很美好,,但是愚蠢的我忘了应该还有一个参数来接收空数组的,我们之前是直接定义了一个变量target 它是一个空数组,相当于我们直接把它写死了,这样如果这个引用类型是一个数组,代码就直接崩掉了。所以需要修改一下,默认是空数组,传了就以它传入的那个为准。

function deepClone(origin target = {}) { }

js深拷贝与浅拷贝的实现方式(JS之实现深度拷贝)(8)

如果第二个参数不传,则它是一个空对象,传了则以它传入的那个参数为准。

则递归只需要这样修改即可:deepClone(origin[prop] target[prop]),第一个参数是要拷贝的引用类型,传入第二个参数来接收。

为了防止最初没有传入第二个参数,则我们可以把克隆的结果return出来, 在执行完函数之后定义一个变量来接收即可!

完整代码:

function deepClone(origin target = {}) { let toStr = Object.prototype.toString let arrStr = '[object Array]' for (prop in origin) { if (origin.hasOwnProperty(prop)) { if (origin[prop] !== null && typeof(origin[prop]) == 'object') { if (toStr.call(origin[prop]) === arrStr) { target[prop] = [] } else { target[prop] = {} } deepClone(origin[prop] target[prop]) } else { target[prop] = origin[prop] } } } return target }

js深拷贝与浅拷贝的实现方式(JS之实现深度拷贝)(9)

试用一下下:

// 定义一个复杂的对象 let obj = { name: 'wgc' age: 20 sex: '男' arr: ['一维数组' ['二维数组' ['三维数组']]] article: { title: '标题' content: '内容' img: '图片' video: '视频' comment: { avatar: '头像' value: '评论' } } } // 克隆它!!! console.log(deepClone(obj)) let obj1 = {} deepClone(obj obj1) console.log(obj1)

js深拷贝与浅拷贝的实现方式(JS之实现深度拷贝)(10)

查看打印结果:

js深拷贝与浅拷贝的实现方式(JS之实现深度拷贝)(11)

嗯。。结局还是很完美的!

猜您喜欢: