先來看一個例子
例一:
var a=[1,2,3]; var b=a; b.push(4); alert(b);//1,2,3,4 alert(a);//1,2,3,4
var a=[1,2,3]; var b=a; b=[1,2,3,4] alert(b);//1,2,3,4 alert(a);//1,2,3
這兩種方法得出的結果是不一樣的。
第一個程序,是對象的引用, 把a的值附給b,a與b之間是引用的關系,當兩者之間是引用的關系時,改變任一變量,都會影響另一個變量。
第二個程序,只是對b的值改變,雖然b=a ,但是當改變b的值時,又重新建立了一個地址,這個地址與a無關,所以在改變b值時,與a無關,這有點類似於C中的指針
再來看一個例子
例二:
var a={ name:'hello' }; var b=a; b.name='hi'; alert(a.name);//當然了,這個結果肯定是hi
如何解決上面的問題呢?
var a={ name:'hello' }; function copy(a){ var b={}; for(var attr in a){ b[attr]=a[attr] } return b } copy(a).name='hi'; alert(a.name); //這時的結果就是hello了
上面的方法叫淺拷貝,利用for in 把a中屬性拷貝給b,但是只是拷貝了一個副本,實際上當修改b的值是不會改變a的值的。當然有淺拷貝就有深拷貝。
var a={ name:{value:'world'} } function copy(a){ var b={}; for(var attr in a){ b[attr]=a[attr]; } return b } copy(a).name.value='space'; alert(a.name.value); //這時的結果是space
這時候大家或許或納悶,用了拷貝了怎么結果還是space呢!因為JSON里面又有一個 value:'world' 這個類型是一個對象,你拷貝過來還是對象,還是對象的引用,所以結果就是space,當然了,或許有會說那就再用一次copy就行。由結果再調用一次copy,對了,就是遞歸的含義,在函數內部調用函數本身。稍微修改一下程序即可
var a={ name:{value:'world'} } function deepCopy(a){ if(typeof a!='object'){ return a } var b={}; for(var attr in a){ b[attr]=deepCopy(a[attr]); } return b } deepCopy(a).name.value='space'; alert(a.name.value); //這時的結果就是world
改的地方有兩處,1、執行函數內部調用函數本身 b[attr]=deepCopy(a[attr]) 2、終止條件typeof a!='object' 就像上面說的,你用淺拷貝拷的是對象,終止條件就是檢測類型不是對象的時候,返回a的值。這樣就解決了問題。 上面的方法就是深拷貝。
例三:
現在了解了淺/深拷貝,想用HTML5方法去解決。在解決之前,我們很有必要去了解HTML5之前如何將字符串轉換成js語句,如下:
var str='function task(){alert('hello')}' var fn=eval(str); task(); //hello
HTML5如何把JSON格式的字符串轉成JSON對象,用JSON.parse() 如下:
var a='{ 'name':'hello'; };' var json=JSON.parse(a); alert(json.name); //hello
這個name上加了 ' ' 不加' ' 是不嚴格的JSON,JSON.parse 方法要求必須是嚴格的JSON
如何將JSON對象轉成JSON格式的字符串呢,用JSON.stringify() 如下:
var a={ name:'hello' }; var json=JSON.stingify(a); alert(json); // '{'name':'hello'}'
這時的結果就是 '{'name':'hello'}',這時候就明白了為什么要用嚴格的JSON格式了
那么用HTML5怎么解決問題呢,那就先把JSON轉成字符串,再把JSON格式的字符換轉成對象,實際上引用的還是a的副本,並沒有真正引用a。這就和拷貝中的
副本原理是一樣的。如下:
var a={ name:'hello' }; var str=JSON.stringify(a); var obj=JSON.parse(str); var b=obj; b.name='hi'; alert(a.name);//hello
拓展:
這種方法實際上在8以下是不兼容的,如何兼容呢,就是引用一個json文件:json2.js,如下
<script type='text/javascript' src='json2.js'></script>