对象混合与克隆
对象混合
对象混合简单来说就是把几个不同的对象组合到一个对象中,比如:
let user = {
name: "jack",
age: 18,
tel: "13898989891"
}
let stu = {
name: "rose",
score: 90,
sex: "女"
}
要混合成一个对象,比如:
{ name: 'rose', age: 18, tel: '13898989891', score: 90, sex: '女' }
在现在ES6的基础上,其实十分的简单,可以使用扩展运算符...
或者Object.assgin()
函数都可一个办到
let u1 = { ...user, ...stu };
//注意Object.assign函数要实现混入,第一个参数最好是空对象,
//因为Object.assign函数会改变一个参数的值
let u2 = Object.assign({}, user, stu);
混入之后,形成了新的对象,这个时候,如果改变原来对象的值,不会对新对象产生影响
let user = {
name: "jack",
age: 18,
tel: "13898989891"
}
let stu = {
name: "rose",
score: 90,
sex: "女",
}
let u2 = Object.assign({}, user, stu);
stu.sex = "男"
console.log(u2);
上面将stu.sex
的值,改为了男
,但是u2打印的sex
值任然是女
。
但是,如果我们的混入的对象,有更深的层次,这个时候,状况就会发生变化
let user = {
name: "jack",
age: 18,
tel: "13898989891"
}
let stu = {
name: "rose",
score: 90,
sex: "女",
teacher: {
name: "Mr.J",
type: "java"
}
}
let u2 = Object.assign({}, user, stu);
console.log(u2);
stu.sex = "男"
stu.teacher.name = "Miss.W";
console.log(u2);
这里打印很明显看到,teacher的名字也随之发生了变化,当然,这是属于对象克隆的问题了
对象克隆
由于众所周知的对象引用传递的问题,如果对象之间直接用=
赋值,改变其中的一个对象的值,另外的也会发生变化。
要改变这个情况,我们当然可以使用扩展运算符...
或者自己去写一个克隆函数就行了
let stu = {
name: "rose",
score: 90,
sex: "女",
teacher: {
name: "Mr.J",
type: "java"
}
}
let s = { ...stu };
stu.name = "jack";
console.log(s);
改变name
的值,新赋值的s
对象的name
并不会发生变化。
我们也可以自己写一个克隆函数:
function clone(obj) {
var newObj = {};
for (var prop in obj) {
newObj[prop] = obj[prop];
}
return newObj;
}
let stu = {
name: "rose",
score: 90,
sex: "女",
teacher: {
name: "Mr.J",
type: "java"
}
}
let s = clone(stu);
stu.name = "jack";
console.log(s);
但是,无论哪种,这种克隆还是只属于所谓的浅克隆,因为只要,克隆对象的层次再深一点,比如对象的属性是一个对象,或者对象的属性是一个数组,那么还是会造成引用传递的问题。
如果要避免这个问题,我们可以将clone克隆函数改写成下面这个样子
/**
* 克隆对象
* @param {any} obj
* @param {boolean} deep true深克隆,false浅克隆
* @returns 克隆对象
*/
function clone(obj, deep) {
if (Array.isArray(obj)) {
// 如果是一个数组
if (deep) {
// 深度克隆
var newArr = []; //定义一个空数组
for (var i = 0; i < obj.length; i++) {
// 循环obj的每一项
newArr[i].push(arguments.callee(obj[i], deep)); // push数组
}
} else {
return obj.slice(); // 复制数组
}
} else if (typeof obj === "object") {
// 如果是一个普通对象
var newObj = {}; // 定义一个对象
for (var prop in obj) {
// 循环obj
if (deep) {
// 如果是深度克隆的话,我们把这个属性的值再克隆一遍【递归】
newObj[prop] = arguments.callee(obj[prop], deep);
} else {
newObj[prop] = obj[prop]; // 添加属性
}
}
return newObj; // 返回
} else {
// 函数、原始类型
return obj; // 直接返回 【递归的终止条件】
}
}
再次使用clone函数,注意第二个参数要传true
let stu = {
name: "rose",
score: 90,
sex: "女",
teacher: {
name: "Mr.J",
type: "java",
},
};
let s = clone(stu,true);
stu.teacher.name = "Miss.W";
console.log(s);
Comments