|
比如:
var str = "string....";
var arr = ["this","is","array"];
var obj = {name:"caizhongqi",age:26,sex:"male"};
這些都是正確的,這似乎非常簡(jiǎn)單方便,但是這種方便也會(huì)帶來(lái)一些令人難于捉摸的意外,看看下面的例子(例1):
<script> var x = "this is string";
var y = x;
x="ni hao";
alert(y)
</script>
你可能一下子知道alert出來(lái)的就是“this is string”,沒(méi)錯(cuò),但對(duì)于用Java語(yǔ)言的程序員來(lái)說(shuō),var y=x 應(yīng)該是把x在存儲(chǔ)器中的地址(指針)賦給y變量才對(duì),因此他們覺(jué)得應(yīng)該alert出“ni hao”才會(huì)更符合Java語(yǔ)言的習(xí)慣,但JavaScript語(yǔ)言不是這樣,字符串的賦值是直接量操作,直接把數(shù)據(jù)copy給y的存儲(chǔ)空間。
再看看下面的例子(例2):
<script>
var x = ["hello"] // 這是一個(gè)數(shù)組,只有一個(gè)元素,并且該元素為字符串類型
var y = x;
x[0] = "world";
alert(y[0]);
</script>
如果你還以為alert出來(lái)的是“hello”,那就錯(cuò)了。當(dāng) var y = x 時(shí),x不是已經(jīng)把它的數(shù)組給了y嗎?但事實(shí)上卻不是這樣, 當(dāng) var y = x 時(shí),x傳的是它在存儲(chǔ)器中的地址(指針)!x[0]="world" 修改了在原存儲(chǔ)位置上的數(shù)據(jù),因此alert(y[0])就是拿x的新值出來(lái)alert。混亂了吧?怎么一會(huì)兒是直接量一會(huì)兒是引用量呢?
不急,下面的例子將更加混亂(例3):
<script>
var x = ["hello"] // 這是一個(gè)數(shù)組,只有一個(gè)元素,并且該元素為字符串類型
var y = x;
x = ["ni","hao"]; // x 將變成一個(gè)新的數(shù)組了。
alert(y[0]);
</script>
你的眼睛告訴你,alert出來(lái)的是“hello”!這讓人捉摸不透古靈精怪的JavaScript!
周星馳的《國(guó)產(chǎn)零零漆》中有類似的一幕:
當(dāng)星爺剛從深圳到香港執(zhí)行任務(wù)時(shí),袁詠儀從他的行李中發(fā)現(xiàn)一個(gè)吹頭發(fā)的風(fēng)筒,星爺說(shuō)這其實(shí)是個(gè)須刨,把皮鞋拿出來(lái)一看卻是一個(gè)風(fēng)筒,一個(gè)貌似大哥大電話的玩意其實(shí)又是一個(gè)須刨。須刨與風(fēng)筒把袁詠儀與觀眾都搞混亂了,哈哈哈哈,這是我很喜歡的一部片,第一次看時(shí)肚子都笑痛了。
回過(guò)頭來(lái)再看看剛才的變量賦值,直接量與引用量的使用,就好像須刨與風(fēng)筒換來(lái)?yè)Q去,把我們都搞暈了。
其實(shí)問(wèn)題出在對(duì)x的第二次賦值 x = ["ni","hao"] 上,我們看看變量在存儲(chǔ)器上變化以及JavaScript在對(duì)待字符串類型與對(duì)象類型的不同:
我們觀察下面兩種情況:
var x = "this is string...";
var y = ["this","is","string"];
x與y不同之處在于類型,Javascript的解析器把字符串直接賦值(其實(shí)就是copy)給x(直接量),卻把數(shù)組的指針賦給y(引用量),這一切都是瞬間全自動(dòng)的!結(jié)合下面的圖,可能會(huì)更好地理解:
圖中p1、p2...就是變量的指針,上面的 var y 中的y存的就是Object類型變量的指針p1(假設(shè)),而x存放的就是字符串本身。再分析一下例3,執(zhí)行 var x = ["hello"] 時(shí),解析器就在內(nèi)存上開(kāi)辟一塊存儲(chǔ)空間放這個(gè)數(shù)組,而 x 就拿到了這個(gè)空間的地址(指針),再執(zhí)行 x = ["ni","hao"] 時(shí),解析器又新開(kāi)辟一塊存儲(chǔ)空間放這個(gè)新數(shù)組,而x就是這個(gè)新存儲(chǔ)空間的指針,這也就是說(shuō),JavaScript 里變量的重定義(或重新賦值)將會(huì)新開(kāi)辟一塊存儲(chǔ)空間,而沒(méi)有銷毀原來(lái)的空間;回過(guò)頭來(lái)再看例2,x[0] = "world",這句沒(méi)有給x新定義值,沒(méi)有新開(kāi)辟存儲(chǔ)空間,只是修改了它存儲(chǔ)空間里面的數(shù)據(jù),因此例2最后alert出來(lái)的就是“world”;例1是字符串賦值,全過(guò)程是直接量操作。
從上面的分析可以看出,JavaScript 的變量可以存儲(chǔ)直接量也可以存儲(chǔ)指針,這是沒(méi)辦法被人工干擾的,因此,在日常的編碼中,就需要注意這些問(wèn)題,比如大字符串連接,循環(huán)里面賦值等細(xì)節(jié)就能直接影響到程序的執(zhí)行效率。
看看兩個(gè)例子:
var _tmpStr="";
var str = "this is big string...";
for (i=0; i<100; i++){
_tmpStr += a;
}
a = _tmpStr;
因?yàn)槭亲址僮鳎褂弥苯恿浚看窝h(huán)都要操作大字符串,非常笨重,效率低下。如果改用引用量操作,即通過(guò)數(shù)組:
var str = "this is big string...";
var _tmpArray = [];
for (i=0; i<100; i++){
_tmpArray[i]=str;
}
str = _tmpArray.join("");
做個(gè)測(cè)試,假如有個(gè)100k的字符串,用直接量連接操作,我的機(jī)器上需要約2600毫秒,如果用數(shù)組連接,則需要150毫秒,效率相差十幾倍。
好久沒(méi)寫(xiě)這么長(zhǎng)的文章了,花了我大半天的時(shí)間。
JavaScript技術(shù):分析 JavaScript 中令人困惑的變量賦值,轉(zhuǎn)載需保留來(lái)源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。