javascript中,变量类型分为基本类型和对象类型,基本类型有以下几种:string,number,boolean,null,undefined,对象类型就是object,object又分为object,array,function。基本类型是值传递,对象类型是引用传递。具体来说,就是基本类型a=1,赋给另一个变量b=a,在操作b的时候,a的值不会随着b的变化而变化。对象类型就不一样了,如a = [1,2],当我们赋值给b=a,对b进行操作,b[0]=2,这时候a也跟着变化a=[2,2]。这就是值传递与引用传递的区别。下面我们看具体的示例:
$(function() {
var a = {name:"aa"};
var b = ["a","b","c"];
var c = a;
c.id = 101;
console.log(a); //{name:"aa",id:101}
var d = b;
d.push("d");
console.log(b);//["a","b","c","d"]
var e = 12;
var f = e;
f = f+1;
console.log(e);//12
});
运行结果如下:
基本类型,值传递,这个没什么好说,但是对象类型引用传递,原因是两个变量公用一个内存,在操作任意变量对象的时候,它们的值都是会发生变化的。那么问题来了,如果需要做到不改变原始变量的值,怎么办,这里就需要解决一个内存问题,就是怎么把两个变量变为两个内存中的地址,而不是共用一块内存,这里就需要用到拷贝。
js中的拷贝分为浅拷贝和深拷贝,所谓浅拷贝就是在变量赋值过程中,只拷贝一级变量,比如a={name:"aa",id:101},b=simpleclone(a),那么name,id都会拷贝过去,当我们修改name,id的值,不会影响到a。
$(function() {
function simpleclone(a){
var res = {};
for (var i in a){
res[i] = a[i];
}
return res;
}
var a = {name:"aa",id:101};
var b = simpleclone(a);
b.id = 102;
console.log(a,b);
});
运行结果如下:
从结果看出,b经过改变,a的值没有发生变化,赋值之后,b与a的关系切断了。基本达到了我们的要求。但是浅拷贝有个问题,就是只是拷贝一级变量,如果一个变量内部有一个嵌套的对象,那么浅拷贝就失去了作用。
$(function() {
function simpleclone(a){
var res = {};
for (var i in a){
res[i] = a[i];
}
return res;
}
var a = {name:"aa",id:101,address:{postcode:100085,detail:"1-3-602"}};
var b = simpleclone(a);
b.id = 102;
console.log(a,b);
b.address.postcode = 100000;
console.log(a,b);
});
运行结果:
当改变一级变量id=102时,a,b的id是不相同的,当我们改变b.address.postcode=100000时,结果a.address.postcode也发生了变化,这就有问题了,浅拷贝不能解决变量嵌套 变量的问题。这就需要深拷贝来解决了。
深拷贝的思路就是在浅拷贝的基础上做了一个判断,如果是对象变量,即变量嵌套变量,那么就需要使用递归来拷贝。
$(function() {
function deepclone(a) {
var res = {};
for(var i in a){
if(typeof a[i]=="object"){
res[i] = deepclone(a[i]);
}else{
res[i] = a[i];
}
}
return res;
}
var a = {name:"aa",id:101,address:{postcode:100085,detail:"1-3-602"}};
var b = deepclone(a);
b.id = 102;
b.address.postcode = 100000;
console.log(a,b);
});
运行结果:(这里的递归拷贝不是一个完美的方法,没有考虑属性是数组的情况)
深拷贝的结果是当b=deepclone(a)之后,对b做的任何改变,都不会影响a,这样就完全解决了对象引用传递带来的问题。深拷贝的实现方式,除了递归拷贝之外,还有几种方式,这里jQuery提供了一种方法$.extend(true,b,a);该方法的第一个参数如果是false,那么就是浅拷贝,只有为true时,才是深拷贝。第二个参数是拷贝前的结果,一般是一个空对象,第三个参数是需要拷贝的对象。 还有一种实现方式就是使用JSON对象提供的方法。
function deepclone(a) {
//return $.extend(true,{},a);
var tmp = JSON.stringify(a);
return JSON.parse(tmp);
}