前端攻城狮的工作实际应用中,处理数据时往往使用数据的深拷贝和浅拷贝
例如,vue中的数据是双向绑定的,页面显示取决于从后台检索的数据,但如果尝试将此数据作为参数发送到其他接口,则某些字段将是多余的。 在这种情况下,如果删除了原始数据中的字段,页面上的某些数据将不再显示,但如果将多余的数据发送到接口,请求将失败。 在这种情况下,请使用深拷贝和轻拷贝。
深拷贝和浅拷贝可以考察人的能力具体是怎么样的,比如基本功、逻辑能力、编码能力等……。
深拷贝和写拷贝主要针对引用型数据。 因为在分配了基本数据类型后,更改新数据不会影响原始数据。 在参照数据类型分配值后,更改新数据会影响原始数据。 在这种情况下,必须使用深拷贝和写拷贝来定义与原始数据相同但互不影响的数据。
注意:赋值操作和深拷贝的写拷贝不是一回事。
分配值
基本型数据的代入
基本数据类型包括number、string、boolean、undefined和null。 这些数据类型相对简单,赋值后两个变量互不影响。
var a=10;
var b=a;
a=20;
控制台. log (a;
控制台. log (b );
此时的b是10。 之所以将a代入b,是因为复制了a空间的值并将其放入了b空间。 改变a只是在改变a空间,不影响b空间。 基本类型赋值
引用类型数据赋值
引用数据类型有Array、Object。 分配相对复杂,分配后的两个变量共享一个数据内存空间,更改其中一个会更改另一个。
vararr=[ 1,2,3 ];
var brr=arr;
ARR.push(4;
控制台. log (arr;
控制台. log (brr;
此时的brr也有4个要素,和arr一模一样。 将arr分配给brr是将存储在arr中的数据空间地址复制并放入brr中,arr和brr共享同一数据空间,因此更改其中一个数据时,另一个地址也会发生变化。 引用数据类型赋值
暗拷贝和轻拷贝的出现是为了解决这个问题。
浅拷贝
浅副本是指将原始数据中的所有数据复制并放置在新的变量空间中。 两个变量不共享一个内存地址。
对象的浅副本
在系统提供的构造函数Object中使用assign方法。
语法:
Object.assign({},原始对象}
//返回到新对象
示例:
var obj={
name:'jwdxy ',
age:12,
gender: '男'
}
varpbj=object.assign (,obj );
控制台. log (obj;
控制台. log (pbj;
此时的pbj是与obj一模一样的对象的浅副本
但是,存储在obj和pbj两个变量中的数据空间地址不同。 示例:
obj.name='清爽的咖啡豆';
obj.age=20;
控制台. log (obj;
控制台. log (pbj;
此时的pbj一点也没有变化。 name键的值仍为“jwdxy”,age键的值仍为12。 因为obj和pbj不共享数据的内存地址。 复制后的地址不同
注意:如果对象中的数据值为引用数据类型,则在创建新对象时,此引用数据类型的地址也会放置在新对象中。
var obj={
name:'jwdxy ',
age:12,
gender: '男人',
wife:{
name: '乐观的月光',
age:11
}
}
varpbj=object.assign (,obj );
obj.wife.gender='女';
控制台. log (obj.wife;
控制台. log (pbj.wife );
此时,与pbj的wife键相对应的对象包含gender键,值为“女”。 如果对象的属性的值是引用类型数据,则浅副本还会复制该引用类型数据的地址。 这意味着新对象不是完全形成的,或者与原始对象有点关联。 这就是浅拷贝。 浅副本的中值为引用类型
数组的浅拷贝
1、阵列系统构建函数原型上的concat方法
vararr=[ 1,2,3 ];
var brr=arr.concat (
ARR.push(4;
con
sole.log(arr);console.log(brr);
此时的brr跟原来的arr是一模一样的,改变了arr后,brr也是没有发生改变的,因为brr的数据空间是一个新的地址。数组浅拷贝-concat
2、Array系统构造函数运行上的slice方法
var arr = [1,2,3];
var brr = arr.slice();
arr.push(4);
cosnole.log(arr);
cosnole.log(brr);
此时的brr跟原来的arr是一模一样的,改变了arr后,brr也是没有发生改变的,因为brr的数据空间是一个新的地址。数组浅拷贝 - slice
注意:如果数组中的数据有引用类型数据,上面两个方法对于数组的拷贝,会将这个引用类型数据的地址也拷贝出来。
var arr = [1,2,[3,4]];
var brr = arr.concat();
arr[2].push(5);
console.log(arr[2]);
console.log(brr[2]);
此时brr的下标2数据中,也会多出5。数组中有引用类型的浅拷贝
slice也是一样的
var arr = [1,2,[3,4]];
var brr = arr.slice();
arr[2].push(5);
console.log(arr[2]);
console.log(brr[2]);
此时brr的下标2数据中,也会多出5。数组中有引用类型的浅拷贝
这就是浅拷贝,如果数据中都是基本类型数据,就是完全没有联系的两个数据,但是如果数据中引用类型数据,那两个变量还是有一定的联系。
所谓浅拷贝,也就是说,数组或对象中的值如果是基本类型数据,那拷贝后的数据和原数据是完全没有关联,且互不影响的两个数据,如果数组或对象的值是引用类型数据的话,拷贝后的数组或对象中的引用类型的值跟原数据中的引用类型的值,还是存在共享同一地址的现象。
深拷贝
深拷贝,就是不管原数据中值是什么类型的数据,拷贝后的新数据跟原数据是完全没有关联的。
1、利用json数据和json字符串之间的转换
var obj = {
name:"jwdxy",
age:12,
wife:{
name:"乐观的月光",
age:20
}
}
var str = JSON.stringify(obj);
var pbj = JSON.parse(str);
obj.wife.gender = '女';
console.log(obj.wife);
console.log(pbj.wife);
此时pbj的wife数据中没有gender键,不受obj的影响。对象深拷贝
数组深拷贝
var arr = [1,2,[3,4]];
var str = JSON.stringify(arr);
var brr = JSON.parse(str);
arr[2].push(5);
console.log(arr[2]);
console.log(brr[2]);
此时brr下标2的数据没有5,不受arr的影响。数组深拷贝
2、利用递归遍历对象或数组
function clone(source){
var result;
if(Object.prototype.toString.call(source)==='[object Object]'){
result = {};
}else if(Object.prototype.toString.call(source)==='[object Array]'){
result = []
}else{
return;
}
for(var attr in source){
if(Object.prototype.toString.call(source[attr])==='[object Array]' || Object.prototype.toString.call(source[attr])==='[object Object]'){
result[attr] = clone(source[attr])
}else{
result[attr] = source[attr];
}
}
return result;
}
使用:
var arr = [1,2,{
name:"jwdxy",
age:12,
wife:{
name:"乐观的月光",
age:11
}
}];
var res = clone(arr)
res[0] = 5;
console.log(arr[0],res[0]); // 1 5
res[2].name = '清爽的咖啡豆'
console.log(arr[2].name,res[2].name); // jwdxy 清爽的咖啡豆
调用函数得到的新数据和原来的数据互不影响。利用递归深拷贝
总之,赋值是赋值,拷贝是拷贝。
浅拷贝,当对象或数组中的数据都是基本数据类型的时候,两个数据之间完全是独立的,如果对象或数组中的值是引用类型的时候,里面是引用类型的值,还是会保持共同的内存地址;
深拷贝出来的两个数据是完全独立的。千锋HTML5学院:教你如何在vue中使用国际化zhuanlan.zhihu.com千锋HTML5学院:axios的请求拦截和vue路由的导航守卫有什么区别zhuanlan.zhihu.com千锋HTML5学院:redux-thunk的理解zhuanlan.zhihu.com