讀古今文學網 > 編寫高質量代碼:改善JavaScript程序的188個建議 > 第2章 字符串、正則表達式和數組 >

第2章 字符串、正則表達式和數組

所有JavaScript程序都與字符串操作緊密相連。例如,許多應用程序利用Ajax從服務器獲取字符串,將這些字符串轉換成更易用的JavaScript對象,然後從數據中生成HTML字符串。一個典型的程序需要處理若幹這樣的任務:合併、分解、重新排列、搜索、遍歷,以及其他方法處理字符串。

在JavaScript中,正則表達式是必不可少的,它的重要性遠超過瑣碎的字符串處理。提高正則表達式效率是很多開發者最易忽視的問題之一。使正則表達式更快地找到匹配,以及在非匹配位置上花費更少時間是開發者必須重視的問題之一。

密集的字符串操作和粗淺地編寫正則表達式是造成JavaScript程序性能問題的主要原因,本章的建議可幫助讀者避免這些常見問題。同時,由於數組是所有數據序列中運算速度最快的一種類型,且JavaScript提供了大量的數組操作方法,這些因素都值得我們去認真研究數組的內部工作機制和應用技巧。

建議34:字符串是非值操作

在字符串的複製和傳遞過程中,JavaScript解釋器以引用方式來實現對字符串的操作。將字符串數據存儲到堆區,然後把字符串的引用地址存儲在字符串變量中。同時為了避免錯誤操作,JavaScript解釋器強制約定字符串在堆區存儲的數據是不可變的。這相當於設置字符串在堆區存儲的數據為「只讀」內容。因此,我們會發現沒有一種JavaScript語法、方法或屬性可以改變字符串中的原字符。

當進行字符串的複製和傳遞時,只是在棧區複製和傳遞字符串的引用地址,這種模擬使用引用的方法進行操作加快了內存的計算速度,不必把所有字符串都讀取到棧區進行操作,這樣節省了大量時間,提高了運行效率,如圖2.1所示。

圖 2.1 引用的字符串

例如,把變量a中的字符串複製給變量b,那麼在b中修改字符串內容,不會影響到a中包含的內容,字符串的複製和傳遞操作像是為字符串建立了獨立的副本。


var a="javascript";

var b=a;

b=b.toUpperCase;

alert(a);

alert(b);


在上面代碼中,最終變量a和b的值是不同的,雖然它們都引用同一個字符串。JavaScript對於字符串的複製和傳遞僅是簡單地採用引用的方法,操作對像為堆區字符串的地址,即複製和傳遞地址。但是,一旦編輯字符串本身的值,JavaScript就會把堆區的字符串讀取到棧區進行獨立操作。

操作完畢,要把結果賦值給原變量,JavaScript需要再次把字符串數據寫回堆區,但沒有覆蓋原值所在的區域,而是新開闢一個區域進行存儲,並把新空間的地址傳遞給棧區的變量進行存儲,也就是說,在堆區新建一個副本。如果不把結果賦值給變量,就待在棧區等待JavaScript垃圾回收,而原來變量的值並沒有改變。所以,在上面代碼中,修改變量b的字符串後,還要把結果字符串賦值給變量b。用示意圖進行演示,如圖2.2所示。

圖 2.2 JavaScript對於字符串的操作過程演示

因此,在操作字符串時,讀者應該注意以下問題:

❑字符串的複製(即賦值)、傳遞(參數傳遞)僅是對字符串的引用進行操作,而不是對字符串本身的值進行操作。

❑修改字符串的值,需要使用值的方法進行操作,而不用修改對字符串的引用。

❑修改字符串的值,不是在堆區原值本身上進行修改,而是通過副本進行修改。

❑修改的字符串副本與原值沒有任何聯繫,如果不把修改值複製給原值變量,則不會對原值產生影響。

❑當把修改的字符串複製給原值變量時,會重新建立一個新的引用,並把修改值存儲到堆區新的位置。

❑原值引用的區域,如果還被其他變量引用,則繼續保留,否則會被JavaScript回收程序回收。