console.log(this.data[i]);
===================================================================
我们只关注数组中的一个代表
举个例子,譬如未改动之前原表单的data和数据库的都是typescript。
第一次改动:
-
我在typescript后面加了个1,即表单的data变成typescript1
-
第一次点击cancel
-
输出结果如下:
console.log(this.data[i]); //typescript1;
console.log(this.dataFormDataBase[i]) //typescript
this.data[i] = this.dataFromDataBase[i];
console.log(this.data[i]); //typescript
- 说明第一次改动后cancel,数据库里的数据dataFromDataBase能够把原本的数据typescript还原给表单中的data,从而起到还原的作用
第二次改动:
-
我还是在原本表单输入框,在typescript后面加个1
-
第二次cancel
-
输出结果
console.log(this.data[i]); //typescript1;
console.log(this.dataFormDataBase[i]) //typescript1
this.data[i] = this.dataFromDataBase[i];
console.log(this.data[i]); //typescript1
??数据库里面的data也变成了typescript1???
为什么第一次dataFromDataBase没有问题,第二次就出现问题了
从此以后,不管怎么cancel,表单输入的值都会保存错误输入的值。
OMG
到这里,这么多疑惑,我们就得去了解一下深拷贝和浅拷贝的内涵了!
等了解了深拷贝和浅拷贝的区别原理,那就知道为什么会出现这样的bug。
再关注一下这一句关于赋值的代码,它在后面讲解是重点对象。
this.data[i] = this.dataFromDataBase[i];
======================================================================
在了解深拷贝和浅拷贝之前,得先了解什么是拷贝copy。
其实在日常敲码的过程中,我们是经常在拷贝copy的。
这个拷贝,就是赋值操作。
赋值: 简单来说就是把某一数值或对象交给另外一个变量。
在JavaScript中,变量只是一个用于保存值的占位符。
1.如果我们赋值赋的只是基本数据类型,那么变量只是保存了这个值。
2. 如果我们赋值的是引用数据类型,那么这个变量实际上保存的是该引用数据的地址。赋值,实际上是赋址。
举个例子再理解一下赋值与“赋址”的区别:
一、基本数据类型:赋值后,两个变量互不影响
let a = ‘coffee’;
let b = a; //赋值
console.log(a); //coffee;
console.log(b); //coffee; 赋值成功
a = ‘milk’;
console.log(a); //milk
console.log(b); //coffee; 赋值后,变量a和变量b并没有关系
二、引用数据类型:赋值后,两个变量保存同一个地址,指向同一个对象,互相有影响。
let a = {
name:‘coffee’,
ice:‘less’
price:30
}
let b = a;
console.log(a);//{ name:‘coffee’,ice:‘less’,price:30};
console.log(b);//{ name:‘coffee’,ice:‘less’,price:30};
a.name = ‘milk’;
a.ice = ‘none’;
a.price = 8;
console.log(a);//{ name:‘milk’,ice:‘none’,price:8};
console.log(b);//{ name:‘milk’,ice:‘none’,price:8};
// 改变a,b也被改变了
// 因为实际上把a赋值给b,b就保存了a指向对象的地址,即a和b保存的是同一个对象的地址,他们都指向同一个对象,都引用了同一个对象。
破案:
到这里,其实我们已经能知道为什么会有上述的bug了:data和dataFromDataBase都是引用数据类型。在第一次cancel时,由于dataFromDataBase赋值给data,那么,data和dataFromDataBase则都引用了同一个对象;在第二次cancel时,当data发生变化,dataFromDataBase也就发生了变化!因为他们都指向同一个对象了。
那怎么办,我们就单纯地只想赋值呀。并不想这二者纠缠不清,表单的数据变了就影响到db的数据。
这时候就需要,深拷贝!进一步了解**什么是浅拷贝,什么是深拷贝!**最后的最后,知道怎么实现深拷贝,就可完结撒花了!
深拷贝有什么用,开门见山:深拷贝之后,两个变量所引用的对象是两个毫无关系的对象,各过各的,互不影响。
深拷贝会拷贝所有的属性,相当于浅拷贝来说时间长开销大。
噢~ ,那深拷贝正合我意,我就是想data和dataFromDataBase两个变量互不影响,我在赋值的时候实现深拷贝就好!
那怎么实现深拷贝?
总结一下实现深拷贝三种方法,具体如何使用可以上文档查看:
-
JSON.stringify,JSON.parse : let b = JSON.parse(JSON.stringify(a));
-
JQ的extend方法:let b = $.extend(true,[],a);
-
lodash的cloneDeep方法:let b = cloneDeep(a);
深拷贝解决bug
这三种方法用哪一种都可以,我发现项目里这一part也有使用lodash的cloneDeep,所以,我也使用cloneDeep()
cancel(){
// change status after ‘cancel’ button clicked
// do something
// 遍历赋值 (关键点!!)
// 还原表单原本的值
for(let i = 0; i < this.data.length; i++){
this.data[i] = cloneDeep(this.dataFromDataBase[i]);
// 使用cloneDeep(),实现深拷贝。
}
// do something
刷面试题
刷题的重要性,不用多说。对于应届生或工作年限不长的人来说,刷面试题一方面能够尽可能地快速自己对某个技术点的理解,另一方面在面试时,有一定几率被问到相同或相似题,另外或多或少也能够为自己面试增加一些自信心,可见适当的刷题是很有必要的。
-
前端字节跳动真题解析
-
【269页】前端大厂面试题宝典
最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。大厂面试远没有我们想的那么困难,摆好心态,做好准备,你也可以的。