浅层克隆
问:把 obj 对象的内容,克隆到 ojb1 上去。
var obj = {
name : 'abc',
age: 123,
sex:"female"
}
var obj1 = {}
分析:这个没有引用值的对象,可以使用浅层克隆。
循环取属性和值(for in),赋给 ojb1 ,再封装起来。
var obj = {
name: 'abc',
age: 123,
sex: "female"
}
var obj1 = {}
function clone(Target, Origin) {
var Target = Target || {}; // 容错,用户输入了 Target 就用,没有就新建个空{}
for (var prop in Origin) {
Target[prop] = Origin[prop];
}
return Target; // 返回
}
clone(obj1, obj);
这里面有个 Target = Target || {} 的用法,用使用了 “或运算” 的特性:遇到真值就返回,意思是:
如何 Target 有值,就用这个 Target ,如果没有,那就给 Target 返回空对象 {} ,简洁,舒服;
效果如控制台:
如果对象比较复杂一点:对象里面还有对象
var obj = {
name: 'abc',
age: 123,
sex: "female",
wife: {
name:"bcd",
age:234,
son:{
name:"cde",
age:345
}
},
card:["visa","unionpay"],
}
看一下结果:
也是可以的。不过对象里有引用值,比如说有个数组的情况:
var obj = {
// ...
card:["visa","unionpay"] // 数组
}
var obj1 = {}
执行完 clone(obj1,obj)后,修改了obj1.card 的内容,也会修改 obj.card 的内容。
有时,这样就不是我们想要的克隆了。
看控制台输出 :
克隆完后,给obj1.card里,push 了新值,原对象 obj.card 里也有了。
所以,把这种克隆叫浅层克隆。
深层克隆
问:把 obj 克隆到 ojb1 里,要求是不能通过 obj1 操作 obj 的内容。
var obj = {
name: 'abc',
age: 123,
sex: "female",
wife: {
name:"bcd",
age:234,
son:{
name:"cde",
age:345
}
},
card:["visa","unionpay"],
}
分析:深层克隆,就是克隆后要,长的一模一样,但就不是一个人。
对于原始值,可以直接 obj[prop] 过去,但引用值就不能这么只这么干了。
假如要克隆对象里的数组,先建个数组对象,然后再循环把数组里的值挨个取出赋给新数组。
问题是对象的属性值也可以是对象,对象里还可以有数组,该怎么弄?
思路:
遍历对象 for(var prop in obj)
1,判断是不是原始值,是就直接赋值;
2,判断是数组还是对象;
3,建立相应的数组或对象。
把原数组或对象当做一个新的对象来赋值 copy 。
数组里面也可能有引用值:就又要先判断是不是原始值,再判断是数组还是对象的过程。
这种周而复始的 123循环 看起来就像是递归。
主要来说是3步,其次是递归这3步;
看下伪代码:
var obj1 = {
name: 'abc',
// 上面三个原始值,直接 copy
// 对象:先建对象
// 看对象内部原始值,挨个 copy
// 对象里的对象也循环挨个 copy
wife: {
name:"bcd",
// ...
son:{
name:"cde",
// ...
}
},
// 数组:先建数组
// 看数组内部的原始值,挨个 copy
card:["visa","unionpay"],
}
知识点:遍历
for in 不仅能遍历对象,也能遍历数组,数组也是特殊类型的对象;
// for(var prop in obj)
var arr = ["a","b","c"];
for(var prop in arr){
arr[prop];
}
控制台输出:
知识点:判断原始值
用 typeof , 如果是 object 都是 引用值;
知识点:判断数组还是对象
三种方法:
1,constructor
2,instanceof
3,toString
看下代码:
function deepClone(origin, target) {
var target = target || {}, // 如果target没定类型,就给他{}
toStr = Object.prototype.toString, // 用于比对数组和对象
arrStr = "[object Array]"; // 数组的返回值,注意大小写
for (var prop in origin) {
if (origin.hasOwnProperty(prop)) { // 判断自有属性
if (typeof (origin[prop]) !== "null" && typeof (origin[prop]) == 'object') {
if (toStr.call(origin[prop]) == arrStr) { // 比对
target[prop] = []; // 是数组给 []
} else {
target[prop] = {}; // 是对象给 {}
}
deepClone(origin[prop], target[prop]); // 递归
} else {
target[prop] = origin[prop]; // 原始值赋值
}
}
}
return target; // 最后返回
}
看控制台输出:
代码还可以用 三目运算符简化一下:
function deepClone(origin, target) {
var target = target || {}, // 如果target没定类型,就给他{}
toStr = Object.prototype.toString, // 用于比对数组和对象
arrStr = "[object Array]"; // 数组的返回值,注意大小写
for (var prop in origin) {
if (origin.hasOwnProperty(prop)) { // 判断自有属性
if (typeof (origin[prop]) !== "null" && typeof (origin[prop]) == 'object') {
target[prop] = (toStr.call(origin[prop]) == arrStr) ? [] : {}
deepClone(origin[prop], target[prop]); // 递归
} else {
target[prop] = origin[prop]; // 原始值赋值
}
}
}
return target; // 最后返回
}