深浅拷贝
基本类型 & 引用类型
ECMAScript中的数据类型可分为两种:
基本类型:undefined,null,Boolean,String,Number,Symbol
引用类型:Object,Array,Date,Function,RegExp等
不同类型的存储方式:
基本类型:基本类型值在内存中占据固定大小,保存在栈内存中
引用类型:引用类型的值是对象,保存在堆内存中,而栈内存存储的是对象的变量标识符以及对象在堆内存中的存储地址
不同类型的复制方式:
基本类型
- 基本类型:从一个变量向另外一个新变量复制基本类型的值,会创建这个值的一个副本,并将该副本复制给新变量
let foo = 1;
let bar = foo;
console.log(foo === bar); // -> true
// 修改foo变量的值并不会影响bar变量的值
let foo = 233;
console.log(foo); // -> 233
console.log(bar); // -> 1
- 引用类型:从一个变量向另一个新变量复制引用类型的值,其实复制的是指针,最终两个变量最终都指向同一个对象
let foo = {
name: 'leeper',
age: 20
}
let bar = foo;
console.log(foo === bar); // -> true
// 改变foo变量的值会影响bar变量的值
foo.age = 19;
console.log(foo); // -> {name: 'leeper', age: 19}
console.log(bar); // -> {name: 'leeper', age: 19}
深拷贝 & 浅拷贝
- 浅拷贝:仅仅是复制了引用,彼此之间的操作会互相影响
- 深拷贝:在堆中重新分配内存,不同的地址,相同的值,互不影响
浅拷贝
- 举一个例子()
var me = {
name: 'zjj',
age: 19,
address: {
home: 'tianjin'
}
};
var me_1 = {
m_token: 'new'
};
function extend(p, c){
var c = c || {};
for(var i in p) {
c[i] = p[i];
}
}
extend(me,me_1);
深拷贝
var me = {
name: 'zjj',
age: 19,
address: {
home: 'tianjin'
}
};
var me_1 = {
m_token: 'new'
};
function extend(p, c){
var c = c || {};
for(var i in p) {
c[i] = p[i];
}
}
function extendDeeply(p, c) {
var c = c || {};
for(var i in p) {
if(typeof p[i] === 'object') {
// 引用类型需要递归实现深拷贝
c[i] = (p[i].constructor === Array ) ? [] : {}
extendDeeply(p[i], c[i]);
} else {
// 非引用类型直接复制即可
c[i] = p[i];
}
}
}
extendDeeply(me,me_1);
- JSON.parse()和JSON.stringify()
JSON.stringify():把一个js对象序列化为一个JSON字符串
JSON.parse():把JSON字符串反序列化为一个js对象
let obj = {
name: 'leeper',
age: 20,
friend: {
name: 'lee',
age: 19
}
};
let copyObj = JSON.parse(JSON.stringify(obj));
obj.name = 'Sandman';
obj.friend.name = 'Jerry';
console.log(obj);
// -> {name: "Sandman", age: 20, friend: {age: 19,name: 'Jerry'}}
console.log(copyObj);
// -> {name: "leeper", age: 20, friend: {age: 19,name: 'lee'}}
综上,JSON.parse()和JSON.stringify()是完全的深拷贝。
动手实现深拷贝 利【递归】来实现对对象或数组的深拷贝。递归思路:对属性中所有引用类型的值进行遍历,直到是基本类型值为止。
// 深拷贝
function deepCopy(obj) {
if (!obj && typeof obj !== 'object') {
throw new Error('error arguments');
}
// const targetObj = obj.constructor === Array ? [] : {};
const targetObj = Array.isArray(obj) ? [] : {};
for (let key in obj) {
//只对对象自有属性进行拷贝
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] === 'object') {
targetObj[key] = deepCopy(obj[key]);
} else {
targetObj[key] = obj[key];
}
}
}
return targetObj;
}
// 测试数据
let a = {
age: undefined,
sex: Symbol('male'),
jobs: function() {
console.log('kkkk')
},
name: 'yck'
}
var cloneA = deepCopy(a);
console.log(cloneA.age);
console.log(cloneA.sex);
cloneA.jobs();
拷贝方式其实也是一种继承的方式,当然继承还是有其他方法的!
(感谢支持!!)