深拷贝与浅拷贝
基本类型的拷贝
先来看一段非常经典的代码
var a = 1;
var b = a;
a = 200;
console.log(a); //200
console.log(b); //1
我们应该知道基本类型“按值传递”,引用类型“按引用传递”,数值作为基本类型是保存在栈内存中,可以直接拿来用的,赋值是什么那么之后就一直是什么,不会受到传递元素的改变带来的影响,所以这里就不难理解上面的代码得到的值的原因了。
引用类型的拷贝
简单说,引用类型是生成一个指针保存的堆内存中,当给引用类型赋值时,我们写的内容是在栈内存中,也就是说我们拿到的其实是一个指针(不会直接拿到栈内存中的内容)。这个指针是指向栈内存中这个引用类型的代码。
浅拷贝针对对象中的基本类型的值生效,但是对引用类型中还有引用类型的情况就会失效。
所谓的深浅拷贝是相对与typeof === 'object' 而言的,数组是用堆对应保存的。
浅拷贝:拷贝了对象的存放地址,只是指向相同而已 (只解决了第一层,对象中还有对象就不适用了)
深拷贝:完全复制了一个独立的个体
- 浅拷贝方法:(直接 =,Object.assign ...扩展运算符(对于对象一级属性是深拷贝,后面的属性都是浅拷贝)大部分都是浅拷贝)
=
let arr1 = [1,3,5];
let arr2 = arr1;
arr1[0] = 10;
console.log(arr2) // [10,3,5]
var obj1 = {
name: '张三'
}
var obj2 = obj1;
obj2.name = '李四';
console.log(obj1.name); // '李四'
Object.assign
var obj1 = {
name: '张三'
}
var obj2 = Object.assign({}, obj1);
obj2.name = '李四';
console.log(obj1.name); // '张三'
至此,浅拷贝成功,但存在兼容性问题,比如低端的安卓机等,这个需要注意。但细心的朋友肯定会再做一个测试,如下:
var obj1 = {
name: '张三',
friends: {
name: '刘备',
age: 33
}
}
var obj2 = Object.assign({}, obj1);
obj2.name = '李四';
obj2.friends.name = '关羽';
console.log(obj1.name); // '张三'
console.log(obj1.friends.name); // '关羽'
是的,到这一步,我们失败了,对象中嵌套对象时,Object.assign()只能拷贝一层,那如何解决呢?其实就要用到深拷贝的方法了:
var obj1 = {
name: '张三',
friends: {
name: '刘备',
age: 33
}
}
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.name = '李四';
obj2.friends.name = '关羽';
console.log(obj1.name); // '张三'
console.log(obj1.friends.name); // '刘备'
- 深拷贝方法:
Json.parse(Json.stringify())
var obj1 = {
name: '张三',
friends: {
name: '刘备',
age: 33
}
}
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.name = '李四';
obj2.friends.name = '关羽';
console.log(obj1.name); // '张三'
console.log(obj1.friends.name); // '刘备'~~~~
lodash
中的_.cloneDeep(value)
方法
返回新数组方法 slice() 、 contat()、 map()(待实践)
let arr1 = [2,5,7];
let arr2 = arr1.slice(0);
let arr3 = arr1.contat();
let arr4 = arr1.map(x => x);
arr2[0] = 4;
arr1[0] = 99;
console.log(arr1,arr2) // [99,5,7] [4,5,7]
for-in连原型链也一并复制的方法 (待实践)
let arr = [1,3,5];
let arr2 = [] ;
for(var key in arr) {
arr2[key] = arr[key]
}
封装方法
/**
* 判断对象类型
* @param {Object} object
* @return {String} object type
*/
getType(object) {
var toString = Object.prototype.toString;
var map = {
'[object Boolean]': 'boolean',
'[object Number]': 'number',
'[object String]': 'string',
'[object Function]': 'function',
'[object Array]': 'array',
'[object Date]': 'date',
'[object RegExp]': 'regExp',
'[object Undefined]': 'undefined',
'[object Null]': 'null',
'[object Object]': 'object'
};
if (object instanceof Element) {
return 'element';
}
return map[toString.call(object)];
},
/**
* 对象的深度拷贝
* @param data 需要拷贝的元数据
* @return {any} 返回拷贝后的新数据
*/
deepClone(data) {
const type = this.getType(data);
let obj;
if (type === 'array') {
obj = [];
} else if (type === 'object') {
obj = {};
} else {
//不再具有下一层次
return data;
}
if (type === 'array') {
for (let i = 0, len = data.length; i < len; i++) {
obj.push(this.deepClone(data[i]));
}
} else if (type === 'object') {
for (let key in data) {
obj[key] = this.deepClone(data[key]);
}
}
const constructor = data.constructor;
if (constructor) {
return Object.assign(new constructor(), obj);
}
return obj;
},
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。