克隆概念

浅复制:原始类型为值传递,对象类型仍为引用传递。

深复制:所有元素或属性均完全复制,与原对象完全脱离,也就是说所有对于新对象的修改都不会反映到原对象中。

浅复制

浅复制就是简单的引用复制

var src = {
    name:"src"
}
//复制一份src对象的应用
var target = src;
target.name = "target";
console.log(src.name);   //输出target

target对象只是src对象的引用值的复制,因此target的改变也会影响src。

深复制

Array的slice和concat方法

Array的slice和concat方法都会返回一个新的数组实例,但是这两个方法对于数组中的对象元素却没有执行深复制,而只是复制了引用了,因此这两个方法并不是真正的深复制,通过以下代码进行理解:

var array = [1,2,3];
var array_shallow = array;
var array_concat = array.concat();
var array_slice = array.slice(0);
console.log(array === array_shallow); //true
console.log(array === array_slice); //false
console.log(array === array_concat); //false
可以看出,concat和slice返回的不同的数组实例,这与直接的引用复制是不同的。
var array = [1, [1,2,3], {name:"array"}];
var array_concat = array.concat();
var array_slice = array.slice(0);
//改变array_concat中数组元素的值
array_concat[1][0] = 5;
console.log(array[1]); //[5,2,3]
console.log(array_slice[1]); //[5,2,3]
//改变array_slice中对象元素的值
array_slice[2].name = "array_slice";
console.log(array[2].name); //array_slice
console.log(array_concat[2].name); //array_slice

通过代码的输出可以看出concat和slice并不是真正的深复制,数组中的对象元素(Object,Array等)只是复制了引用

JSON对象的parse和stringify

JSON对象是ES5中引入的新的类型(支持的浏览器为IE8+),JSON对象parse方法可以将JSON字符串反序列化成JS对象,stringify方法可以将JS对象序列化成JSON字符串,借助这两个方法,也可以实现对象的深复制。

var source = {
    name:"source",
    child:{
        name:"child"
    }
}
var target = JSON.parse(JSON.stringify(source));
//改变target的name属性
target.name = "target";
console.log(source.name);   //source
console.log(target.name);   //target
//改变target的child
target.child.name = "target child";
console.log(source.child.name);  //child
console.log(target.child.name);  //target child

从代码的输出可以看出,复制后的target与source是完全隔离的,二者不会相互影响。 这个方法使用较为简单,可以满足基本的深复制需求,而且能够处理JSON格式能表示的所有数据类型,但是对于正则表达式类型、函数类型等无法进行深复制(而且会直接丢失相应的值),同时如果对象中存在循环引用的情况也无法正确处理

jQuery中的extend复制方法

jQuery中的extend方法可以用来扩展对象,这个方法可以传入一个参数:deep(true or false),表示是否执行深复制(如果是深复制则会执行递归复制)

自己实现一个copy方法
//util作为判断变量具体类型的辅助模块
var util = (function () {
    var class2type = {};
    ["Null", "Undefined", "Number", "Boolean", "String", "Object", "Function", "Array", "RegExp", "Date"].forEach(function (item) {
        class2type["[object " + item + "]"] = item.toLowerCase();
    });

    function isType(obj, type) {
        return getType(obj) === type;
    }

    function getType(obj) {
        return class2type[Object.prototype.toString.call(obj)] || "object";
    }
    return {
        isType: isType,
        getType: getType
    }
})();

function copy(obj, deep) {
    //如果obj不是对象,那么直接返回值就可以了
    if (obj === null || typeof obj !== "object") {
        return obj;
    }
    //定义需要的局部变量,根据obj的类型来调整target的类型
    var i, target = util.isType(obj, "array") ? [] : {},
        value, valueType;
    for (i in obj) {
        value = obj[i];
        valueType = util.getType(value);
        //只有在明确执行深复制,并且当前的value是数组或对象的情况下才执行递归复制
        if (deep && (valueType === "array" || valueType === "object")) {
            target[i] = copy(value);
        } else if (deep && valueType !== "array" && valueType !== "object") {
            target[i] = eval(value.toString());
        } else {
            target[i] = value;
        }
    }
    return target;
}
Copyright © Eternally all right reserved,powered by Gitbookmodified at 2019-07-17 06:20:46

results matching ""

    No results matching ""