gogoend / blog

blogs, ideas, etc.
MIT License
9 stars 2 forks source link

对象深拷贝各种姿势尝试 #28

Open gogoend opened 4 years ago

gogoend commented 4 years ago

背景

近日做公司的一个Vue.js项目的时,需要这样一个需求:在页面上的选项卡切换后,再返回当前选项卡,需保留选项卡的状态,例如选项卡里表单中的值。

事实上,这样的需求,可以直接用v-show,或者keep-alive来实现。

(所以keep-alive到底咋用??)

无奈之前甲方要求过于急躁,而iView组件的选项卡实在弄不出来,有Bug(所以我并不是很信任别人的组件),keep-alive之前我也没用过,所以只好自己以最笨的方法实现了一个选项卡。

最终选项卡渲染以后,选项卡上方标签使用v-for遍历有多个,下方选项卡组件只有一个 —— 标签页的切换实质上是数据的回填过程;为保存当前选项卡的数据,使得切换回来后能够回填数据,需要对数据进行一次深拷贝进行存储。

之前拷贝使用的是超级常用的JSON序列化反序列化。

let clonedObj = JSON.parse( JSON.stringify( obj ) )

在对日期进行操作的时候,发生了一些错误:

JSON序列化反序列化日期时,执行了Date的toJSON方法,最终拷贝到的日期是一个字符串;回填数据的时候,将日期字符串进行分割(.split('T')[0]),取到前部分年月日(iview日期选择器不会进行判断),此时由于时区问题,时间向前减了一天,每次切换,回填一次,就减去一天。

例如,现在是北京时间2020年5月22日

image

若按照这种方式取得年月日,最终取得的时间是2020年5月21日

由此可见,JSON序列化反序列化的深拷贝在遇到日期等复杂对象时,会变得不再可靠。

gogoend commented 4 years ago

递归拷贝测试

这里是我根据网上找的资料写出的递归深拷贝的方法。

o是原始对象,newO是目标对象。

逻辑大致是,通过原始对象o的key,访问对象中的value。

如果value是数组或是对象,那就新定义一个临时容器,存储将会访问的数组或对象中的值。递归调用这个函数,访问value中的内容,赋值给临时容器。

否则(如果value是基本数据类型)就直接将值赋值给目标对象对应的key。

function deepCopy(o, newO) {
    for (let key in o) {
        if (o[key] instanceof Object) {
            let tempO = o.constructor === Array ? [] : {}
            deepCopy(o[key], tempO)
            newO[key] = tempO
        } else {
            newO[key] = o[key]
        }
    }
}

(完了我其实已经晕了)