javascript.basics icon indicating copy to clipboard operation
javascript.basics copied to clipboard

浅复制与深复制(克隆)

Open Kelichao opened this issue 9 years ago • 1 comments

JS复制

JS中对象,数组,函数都是通过引用传递的,因此如果只是单纯的赋值,仅仅是将对象的地址 进行引用,并不是正真的复制。需要一个一个进行处理。

浅度复制(改变原始对象值对新对象有影响)


// 对象要求:属性中有对象,且该内部对象有简单类型。
var person = {
	name: "Bob",
	sing:{
		"name":"发如雪"
	}
};

进行浅复制

function clone(object) {
    var finalObject = {};
        for (var i in object) {
                finalObject[i] = object[i];
        }
        return finalObject;
}

var x =clone(person);
person.sing.text = "";
console.log(x);
  • text的值被覆盖掉了,所以浅复制引用了同一份 image

如图,当原对象的text被改变之后,克隆出来的对象也被改变了,说明只是进行了浅度复制。

深度复制函数


// 用递归方法拷贝深层次对象
function clone3(cont) {

	//这里增加了数组处理,暂时还不清楚函数体如何进行复制。
	var object = (cont instanceof Array) ? [] : {};

	for (var i in cont) {
		
		// 如果是一个引用对象			
		if (cont[i] instanceof Object === true) {

			// 要用object[i] = agruments.callee
			// 代替object[i] = clone3(cont[i]);
			object[i] = arguments.callee(cont[i]); 	

		// 如果是一个简单对象,则直接赋值		
		} else {
			object[i] = cont[i];		
		}
	} 
	return object;
}
  • 同样执行上述代码
	// 对象要求:属性中有对象,且该内部对象有简单类型。
	var person = {
		name: "Bob",
		sing:{
			"name":"发如雪"
		}
	};


	var x =clone3(person);
	person.sing.text = "";
	console.log(x);
  • text值并没有被改变 image

用arguments.callee与直接使用函数名的区别,可以防止此类错误。

function people() {
    console.log(111);
    people();
};
var anoPeople = people;
people = null;
anoPeople();// Uncaught TypeError: people is not a function

【模仿函数递归调用】时的层级,是从最里面开始生成,最终生成a对象

//函数递归调用的特点
var a = function() {
	return {"a":(function(){
		return {"b": (function() {
			return {"c":(function(){
				return "myValue";
			})()};
				})()
			};
		})()
	};
};
console.log(a());

image

补充下傻瓜递归

	// 傻瓜式递归
	if(b instanceof Object === true) {
		for(var i in b) {
			obj[i] = b[i];
			if(b[i] instanceof Object === true) {
				for(var j in b[i]) {
					obj[i][j] = b[i][j];
					if(b[i][j] instanceof Object === true) {
						for(var m in b[i][j]) {
							obj[i][j][m] = b[i][j][m];
						}
					}
				}
			}
		}
	}

别人博客借鉴,方法类似

function clone2(obj) {
	var o,i,j,k;

	// 是不是简单值
	if (typeof(obj)!="object" || obj===null) {
		return obj;
	}

	//是不是数组
	if(obj instanceof(Array)){
		o=[];
		i=0;j=obj.length;
		for(;i<j;i++){
			if (typeof(obj[i])=="object" && obj[i]!=null) {
				o[i]=arguments.callee(obj[i]);
			}
			else {
				o[i]=obj[i];
			}
		}

	//是不是对象
	} else {
		o={};
		for(i in obj) {
			if (typeof(obj[i])=="object" && obj[i]!=null) {
				o[i]=arguments.callee(obj[i]);
			} else {
				o[i]=obj[i];
			}
		}
	}
 
	return o;
}

优化了网友的写法

  • 1.实现一个函数clone,可以对JavaScript中的5种主要的数据类型(包括Number、String、Object、Array、Boolean)进行值复制

function clone(total) {
	var res = null;
	var flag = function() {
		return typeof(total) != "object" || total === null;
	};

	// 是不是简单类型
	if (flag(total)) {
		return total;
	}

	// 引用类型区分对象/数组
	if (total instanceof Object) {
		res = {};
		for (var i in total) {
			if (flag(total[i])) {
				return arguments.callee(total[i]);
			} else {
				res[i] = total[i];
			}
		}
	} else if (total instanceof Array) {
		res = [];
		for (var j = 0; j < total.length; j++) {
			if (flag(total[j])) {
				return arguments.callee(total[j]);
			} else {
				res[j] = total[j];
			}
		}
	}
	return res;
}

使用while处理的方法


/**
 * 克隆一个对象
 * @param Obj
 * @returns
 */
function clone(Obj) {
    var buf;
    if (Obj instanceof Array) {
        buf = []; //创建一个空的数组
        var i = Obj.length;
        while (i--) {
            buf[i] = clone(Obj[i]);
        }
        return buf;
    } else if (Obj instanceof Object) {
        buf = {}; //创建一个空对象
        for (var k in Obj) { //为这个对象添加新的属性
            buf[k] = clone(Obj[k]);
        }
        return buf;
    } else { //普通变量直接赋值
        return Obj;
    }
}

Kelichao avatar Oct 29 '16 15:10 Kelichao

通过内部函数进行功能区分

function clone(total) {
    var container;

    // 判断是否是引用对象
    function _flag(total) {
        if (typeof total === "object") {
            return true;
        } else {
            return false;
        }
    }

    // 区分数组与对象并进行处理
    function _referType(total) {
        if (total instanceof Array) {
            container =  new Array();
            for (var i = 0; i < total.length; i++) {
                if (_flag(total) === false) {
                    container.push(total[i]);
                } else {
                    container.push(_referType.caller(total[i]));
                }
            }
            return container;
        } else if (total instanceof Object) {
            container = new Object();
            for (var i in total) {
                if (_flag(total) === false) {
                    container[i] = total[i];
                } else {
                    container[i] = _referType.caller(total[i]);
                }
            }
            return container;
        }
    }

    //引用对象
    if (_flag(total)) {
        return _referType(total);
    } else {
        return total;
    }
}

Kelichao avatar Feb 04 '17 09:02 Kelichao