分析 JavaScript 中令人困惑的變數賦值

來源:互聯網
上載者:User

Javascript是一門弱類型的語言,聲明變數不需要聲明其類型,var x 就可以等於任何類型的值。
比如:

var str = "string....";
var arr = ["this","is","array"];
var obj = {name:"caizhongqi",age:26,sex:"male"};
這些都是正確的,這似乎非常簡單方便,但是這種方便也會帶來一些令人難於捉摸的意外,看看下面的例子(例1):

<script> var x = "this is string";
var y = x;
x="ni hao";
alert(y)
</script>

你可能一下子知道alert出來的就是“this is string”,沒錯,但對於用Java語言的程式員來說,var y=x 應該是把x在儲存空間中的地址(指標)賦給y變數才對,因此他們覺得應該alert出“ni hao”才會更符合Java語言的習慣,但JavaScript語言不是這樣,字串的賦值是直接量操作,直接把資料copy給y的儲存空間。

再看看下面的例子(例2):

<script>
var x = ["hello"] // 這是一個數組,只有一個元素,並且該元素為字串類型
var y = x;
x[0] = "world";
alert(y[0]);
</script>

如果你還以為alert出來的是“hello”,那就錯了。當 var y = x 時,x不是已經把它的數組給了y嗎?但事實上卻不是這樣, 當 var y = x 時,x傳的是它在儲存空間中的地址(指標)!x[0]="world" 修改了在原儲存位置上的資料,因此alert(y[0])就是拿x的新值出來alert。混亂了吧?怎麼一會兒是直接量一會兒是引用量呢?
不急,下面的例子將更加混亂(例3):

<script>
var x = ["hello"] // 這是一個數組,只有一個元素,並且該元素為字串類型
var y = x;
x = ["ni","hao"]; // x 將變成一個新的數組了。
alert(y[0]);
</script>

你的眼睛告訴你,alert出來的是“hello”!這讓人捉摸不透古靈精怪的JavaScript!

周星馳的《國產零零漆》中有類似的一幕:
當星爺剛從深圳到香港執行任務時,袁詠儀從他的行李中發現一個吹頭髮的風筒,星爺說這其實是個須刨,把皮鞋拿出來一看卻是一個風筒,一個貌似大哥大電話的玩意其實又是一個須刨。須刨與風筒把袁詠儀與觀眾都搞混亂了,哈哈哈哈,這是我很喜歡的一部片,第一次看時肚子都笑痛了。

回過頭來再看看剛才的變數賦值,直接量與引用量的使用,就好像須刨與風筒換來換去,把我們都搞暈了。
其實問題出在對x的第二次賦值 x = ["ni","hao"] 上,我們看看變數在儲存空間上變化以及JavaScript在對待字串類型與物件類型的不同:

我們觀察下面兩種情況:
var x = "this is string...";
var y = ["this","is","string"];

x與y不同之處在於類型,javascript的解析器把字串直接賦值(其實就是copy)給x(直接量),卻把數組的指標賦給y(引用量),這一切都是瞬間全自動的!結合下面的圖,可能會更好地理解:

圖中p1、p2...就是變數的指標,上面的 var y 中的y存的就是Object類型變數的指標p1(假設),而x存放的就是字串本身。再分析一下例3,執行 var x = ["hello"] 時,解析器就在記憶體上開闢一Block Storage空間放這個數組,而 x 就拿到了這個空間的地址(指標),再執行 x = ["ni","hao"] 時,解析器又新開闢一Block Storage空間放這個新數組,而x就是這個新儲存空間的指標,這也就是說,JavaScript 裡變數的重定義(或重新賦值)將會新開闢一Block Storage空間,而沒有銷毀原來的空間;回過頭來再看例2,x[0] = "world",這句沒有給x新定義值,沒有新開闢儲存空間,只是修改了它儲存空間裡面的資料,因此例2最後alert出來的就是“world”;例1是字串賦值,全過程是直接量操作。

從上面的分析可以看出,JavaScript 的變數可以儲存直接量也可以儲存指標,這是沒辦法被人工幹擾的,因此,在日常的編碼中,就需要注意這些問題,比如大字串串連,迴圈裡面賦值等細節就能直接影響到程式的執行效率。

看看兩個例子:

var _tmpStr="";
var str = "this is big string...";
for (i=0; i<100; i++){
_tmpStr += a;
}
a = _tmpStr;

因為是字串操作,使用直接量,每次迴圈都要操作大字串,非常笨重,效率低下。如果改用引用量操作,即通過數組:

var str = "this is big string...";
var _tmpArray = [];
for (i=0; i<100; i++){
_tmpArray[i]=str;
}
str = _tmpArray.join("");

做個測試,假如有個100k的字串,用直接量串連操作,我的機器上需要約2600毫秒,如果用數組串連,則需要150毫秒,效率相差十幾倍。

好久沒寫這麼長的文章了,花了我大半天的時間。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.