javascript值傳遞與引用傳遞
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);
}