克隆
一、对象的克隆
Javascript中的数据类型分为两大类:原始类型和对象类型。
(1)原始类型包括:数值、字符串、布尔值、null、undefined。
(2)对象类型包括:对象即是属性的集合,当然这里又两个特殊的对象----函数(js中的一等对象)、数组(键值的有序集合)。
这两种类型在复制克隆的时候是有很大区别的。原始类型存储的是对象的实际数据,而对象类型存储的是对象的引用地址(对象的实际内容单独存放,为了减少数据开销通常存放在内存中)。
二、克隆的概念
浅度克隆:原始类型为值传递,对象类型仍为引用传递。
深度克隆:所有元素或属性均完全复制,与原对象完全脱离,也就是说所有对于新对象的修改都不会反映到原对象中。
三、浅层克隆
简单的克隆一般都能写出来,将这个对象克隆过去不就是把它在被克隆对象里面复制一下。浅层克隆非常简单:
//浅层克隆
var obj = {
name : 'json',
age : 34,
sex : 'male',
card : ['visa','unionpay']
}
var obj1 = {};
function clone(origin,target){
var target = target || {};
for(var prop in origin){
target[prop] = origin[prop];
}
return target;
}
clone(obj,obj1);
运行结果:
从上面的运行结果能够看出给原始值克隆容易实现。但是如果给obj1(克隆对象)的引用值(例如数组)增加数组元素。两个对象的card数组都发生了变化。这就产生了bug。
四、深层克隆
从浅层克隆可以看出原始值的克隆没有问题,但是引用值得改变会让被克隆对象发生改变,然而我们本意是只想克隆,然后自己添加元素,并不想改变克隆对象的元素。
设计思想:
遍历对象 for(var prop in obj)
1.判断是不是原始值 typeof() Object
2.判断是数组还是对象 instanceof toString constructor
3.建立相应的数组或对象
递归
这五大步骤即可实现深层克隆,即改变obj1不会改变obj得元素,代码实现:
function deepClone(origin,target){
var target = target || {},
toStr = Object.prototype.toString,
arrStr = "[object Array]"; //数组类型
for(var prop in origin){
if(origin.hasOwnProperty(prop)){
//不为空以及不是原始值
if(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;
}
运行结果:
other :
function deepClone(origin,target){
var target = target || {},
toStr = Object.prototype.toString,
arrStr = "[object Array]"; //数组类型
for(var prop in origin){
if(origin.hasOwnProperty(prop)){
//不为空以及不是原始值
if(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;
}