tring類型
String 類型是字符串的對象包裝類型,可以像下面這樣使用 String 構造函數來創建。
String 對象的方法也可以在所有基本的字符串值中訪問到。其中,繼承的 valueOf()、toLocale- String()和 toString()方法,都返回對象所表示的基本字符串值。
String 類型的每個實例都有一個 length 屬性,表示字符串中包含多個字符。
var stringValue="hello world"; alert(stringValue.length); //"11"
這個例子輸出了字符串"hello world"中的字符數量,即"11"。應該注意的是,即使字符串中包 含雙字節字符(不是占一個字節的 ASCII 字符),每個字符也仍然算一個字符。
String 類型提供了很多方法,用于輔助完成對 ECMAScript 中字符串的解析和操作。
1.字符方法
兩個用于訪問字符串中特定字符的方法是:charAt()和 charCodeAt()。這兩個方法都接收一個 參數,即基于 0 的字符位置。其中,charAt()方法以單字符字符串的形式返回給定位置的那個字符 (ECMAScript 中沒有字符類型)。
var stringValue="hello world"; alert(stringValue.charAt(1)); //"e"
字符串"hello world"位置 1 處的字符是"e",因此調用 charAt(1)就返回了"e"。如果你想得到 的不是字符而是字符編碼,那么就要像下面這樣使用 charCodeAt()了。
var stringValue="hello world"; alert(stringValue.charCodeAt(1)); //輸出"101"
這個例子輸出的是"101",也就是小寫字母"e"的字符編碼。
ECMAScript 5 還定義了另一個訪問個別字符的方法。在支持此方法的瀏覽器中,可以使用方括號加數 字索引來訪問字符串中的特定字符,
var stringValue="hello world"; alert(stringValue[1]); //"e"
使用方括號表示法訪問個別字符的語法得到了 IE8 及 Firefox、Safari、Chrome 和 Opera 所有版本的 支持。如果是在 IE7 及更早版本中使用這種語法,會返回 undefined 值(盡管根本不是特殊的 6 undefined 值)。
2.字符串操作方法
第一個就是 concat(),用于將一或多個字符串拼接起來,返回拼接得到的新字符串。
var stringValue="hello "; var result=stringValue.concat("world"); alert(result); //"hello world" alert(stringValue); //"hello"
在這個例子中,通過 stringValue 調用 concat()方法返回的結果是"hello world"——但 stringValue 的值則保持不變。實際上,concat()方法可以接受任意多個參數,也就是說可以通過它 9 拼接任意多個字符串。
var stringValue="hello "; var result=stringValue.concat("world", "!"); alert(result); //"hello world!" alert(stringValue); //"hello"
這個例子將"world"和"!"拼接到了"hello"的末尾。雖然 concat()是專門用來拼接字符串的方 11 法,但實踐中使用更多的還是加號操作符(+)。而且,使用加號操作符在大多數情況下都比使用 concat() 方法要簡便易行(特別是在拼接多個字符串的情況下)。
ECMAScript 還提供了三個基于子字符串創建新字符串的方法:slice()、substr()和 substring()。 12 這三個方法都會返回被操作字符串的一個子字符串,而且也都接受一或兩個參數。第一個參數指定子字 符串的開始位置,第二個參數(在指定的情況下)表示子字符串到哪里結束。具體來說,slice()和 substring()的第二個參數指定的是子字符串最后一個字符后面的位置。而 substr()的第二個參數指定的則是返回的字符個數。如果沒有給這些方法傳遞第二個參數,則將字符串的長度作為結束位置。與 concat()方法一樣,slice()、substr()和 substring()也不會修改字符串本身的值——它們只是 返回一個基本類型的字符串值,對原始字符串沒有任何影響。
var stringValue="hello world"; alert(stringValue.slice(3)); alert(stringValue.substring(3)); alert(stringValue.substr(3)); alert(stringValue.slice(3, 7)); alert(stringValue.substring(3,7)); alert(stringValue.substr(3, 7)); //"lo world" //"lo world" //"lo world" //"lo w" //"lo w" //"lo worl"
這個例子比較了以相同方式調用 slice()、substr()和 substring()得到的結果,而且多數情 況下的結果是相同的。在只指定一個參數 3 的情況下,這三個方法都返回"lo world",因為"hello" 中的第二個"l"處于位置 3。而在指定兩個參數 3 和 7 的情況下,slice()和 substring()返回"lo w" ("world"中的"o"處于位置 7,因此結果中不包含"o"),但 substr()返回"lo worl",因為它的第二 個參數指定的是要返回的字符個數。
在傳遞給這些方法的參數是負值的情況下,它們的行為就不盡相同了。其中,slice()方法會將傳 入的負值與字符串的長度相加,substr()方法將負的第一個參數加上字符串的長度,而將負的第二個 參數轉換為 0。最后,substring()方法會把所有負值參數都轉換為 0。
var stringValue="hello world"; alert(stringValue.slice(-3)); alert(stringValue.substring(-3)); alert(stringValue.substr(-3)); alert(stringValue.slice(3, -4)); alert(stringValue.substring(3, -4)); alert(stringValue.substr(3, -4)); //"rld" //"hello world" //"rld" //"lo w" //"hel" //""(空字符串)
這個例子清晰地展示了上述三個方法之間的不同行為。在給 slice()和 substr()傳遞一個負值 參數時,它們的行為相同。這是因為-3 會被轉換為 8(字符串長度加參數 11+(?3)=8),實際上相當 于調用了 slice(8)和 substr(8)。但 substring()方法則返回了全部字符串,因為它將-3 轉換 成了 0。
當第二個參數是負值時,這三個方法的行為各不相同。slice()方法會把第二個參數轉換為 7,這 就相當于調用了 slice(3,7),因此返回"lo w"。substring()方法會把第二個參數轉換為 0,使調 用變成了 substring(3,0),而由于這個方法會將較小的數作為開始位置,將較大的數作為結束位置, 因此最終相當于調用了 substring(0,3)。substr()也會將第二個參數轉換為 0,這也就意味著返回 包含零個字符的字符串,也就是一個空字符串。
3.字符串位置方法
有兩個可以從字符串中查找子字符串的方法:indexOf()和 lastIndexOf()。這兩個方法都是從 一個字符串中搜索給定的子字符串,然后返子字符串的位置(如果沒有找到該子字符串,則返回-1)。 這兩個方法的區別在于:indexOf()方法從字符串的開頭向后搜索子字符串,而 lastIndexOf()方法 是從字符串的末尾向前搜索子字符串。
var stringValue="hello world"; alert(stringValue.indexOf("o")); //4 alert(stringValue.lastIndexOf("o")); //7
子字符串"o"第一次出現的位置是 4,即"hello"中的"o";最后一次出現的位置是 7,即"world"中的 "o"。如果"o"在這個字符串中僅出現了一次,那么 indexOf()和 lastIndexOf()會返回相同的位置值。
這兩個方法都可以接收可選的第二個參數,表示從字符串中的哪個位置開始搜索。換句話說, indexOf()會從該參數指定的位置向后搜索,忽略該位置之前的所有字符;而 lastIndexOf()則會從 指定的位置向前搜索,忽略該位置之后的所有字符。
var stringValue="hello world"; alert(stringValue.indexOf("o", 6)); //7 alert(stringValue.lastIndexOf("o", 6)); //4
在將第二個參數 6 傳遞給這兩個方法之后,得到了與前面例子相反的結果。這一次,由于 indexOf()是從位置 6(字母"w")開始向后搜索,結果在位置 7 找到了"o",因此它返回 7。而 last- IndexOf()是從位置 6 開始向前搜索。結果找到了"hello"中的"o",因此它返回 4。在使用第二個 參數的情況下,可以通過循環調用 indexOf()或 lastIndexOf()來找到所有匹配的子字符串,如下 面的例子所示:
var stringValue="Lorem ipsum dolor sit amet, consectetur adipisicing elit"; var positions=new Array(); var pos=stringValue.indexOf("e"); while(pos > -1){ positions.push(pos); pos=stringValue.indexOf("e", pos + 1); } alert(positions); //"3,24,32,35,52"
這個例子通過不斷增加 indexOf()方法開始查找的位置,遍歷了一個長字符串。在循環之外,首 先找到了"e"在字符串中的初始位置;而進入循環后,則每次都給 indexOf()傳遞上一次的位置加 1。 這樣,就確保了每次新搜索都從上一次找到的子字符串的后面開始。每次搜索返回的位置依次被保存在 數組 positions 中,以便將來使用。
、string類型
string類型用于表示由零或多個16位Unicode字符組成的字符序列,即字符串。字符串可以由雙引號或單引號表示,下面兩種字符串的寫法都是有效的:
var firstName="Nicholas"; var lastName='zakas';
與PHP中的雙引號和單引號會影響對字符串的解釋方式不同,ECMAScript中的這兩種語法形式沒有什么區別。用雙引號表示的字符串和單引號表示的字符串完全相同。不過,以雙引號開頭的字符串也必須以雙引號結尾,而以單引號開頭的字符串必須以單引號結尾。
二、字符字面量
string數據類型包含一些特殊的字符字面量,也叫轉義字符,用于表示非打印字符,或者具有其他用途的字符。這些字符字面量如下表所示:
這些字符字面量可以出現在字符串的任意位置,而且會被當作一個字符來解析,來看下面的例子:
var text="This is the letter sigma: \u03a3"; alert(text.length); //輸出28
這個例子中的變量text有28個字符,其中6個字符長的轉義序列表示1個字符。任何字符串的長度都可以通過訪問其length屬性取得。
三、轉換為字符串
要不一個值轉換為一個字符串有三種方式。
1、toString()方法
第一種是使用幾乎每個值都有的toString()方法,這個方法唯一要做的就是返回相應值的字符串表現。數值、布爾值、對象和字符串值都有toString()方法,但null和undefined值沒有這個方法。
var age=11; var ageAsString=age.toString(); //字符串"11" var found=true; var foundAsString=found.toString(); //字符串"true"
多數情況下,調用toString()方法不必傳遞參數。但是,在調用數值的toString()方法時,可以傳遞一個參數:輸出數值的基數。默認情況下,toString()方法以十進制格式返回數值的字符串表示。而通過傳遞基數,toString()可以輸出以二進制、八進制、十六進制。如下所示:
var num=10; alert(num.toString()); //"10" alert(num.toString(2)); //"1010" alert(num.toString(8)); //"12" alert(num.toString(10)); //"10" alert(num.toString(16)); //"a"
2、String()方法
在不知道要轉換的值是不是null或undefined的情況下,還可以使用轉型函數String(),這個函數能夠將任何類型的值轉換為字符串。String()函數遵循下列轉換規則:
var value1=10; var value2=true; var value3=null; var value4; alert(String(value1)); //"10" alert(String(value2)); //"true" alert(String(value3)); //"null" alert(String(value4)); //"undefined"
3、利用加號操作符
要把某個值轉換為字符串,可以使用加號操作符把它與一個字符串(“”)加在一起。
JavaScript中,所有的string類型(或者被稱為DOMString)都是使用UTF-16編碼的。
MDN
DOMString 是一個UTF-16字符串。由于JavaScript已經使用了這樣的字符串,所以DOMString 直接映射到 一個String。
將 null傳遞給接受DOMString的方法或參數時通常會把其stringifies為“null”。
引出的Unicode中UTF-8與UTF-16編碼的詳細了解
Unicode(統一碼、萬國碼、單一碼)是計算機科學領域里的一項業界標準,包括字符集、編碼方案等。Unicode 是為了解決傳統的字符編碼方案的局限而產生的,它為每種語言中的每個字符設定了統一并且唯一的二進制編碼,以滿足跨語言、跨平臺進行文本轉換、處理的要求。1990年開始研發,1994年正式公布。
通常Unicode編碼是通過2 Byte來表示一個字符的,如U+A12B,2 Byte的二進制表示方法結果就是1010(A)0001(1) 0010(2)1011(B)。
需要注意的是:UTF是Unicode TransferFormat的縮寫,UTF-8和UTF-16都是把Unicode碼轉換成程序數據的一種編碼方式。
UTF-8(8-bit Unicode Transformation Format)是一種針對Unicode的可變長度字符編碼,又稱萬國碼。由Ken Thompson于1992年創建。現在已經標準化為RFC 3629。UTF-8用1到6個字節編碼Unicode字符(盡管如此,2003年11月UTF-8被RFC 3629重新規范,只能使用原來Unicode定義的區域,U+0000到U+10FFFF,也就是說最多4個字節)。用在網頁上可以統一頁面顯示中文簡體繁體及其它語言(如英文,日文,韓文)。
UTF-8的來歷
UTF-8的規范里充斥著這樣神秘的句子:“第一個位元組由110開始,接著的位元組由10開始”,“第一個位元組由1110開始,接著的位元組由10開始”。
那么這到底是什么意思呢?為什么要這么做呢?
我們先從二進制說起。我們都知道,一個字節是由8個二進制位構成的,最小就是0000 0000,最大就是1111 1111。那么一個字節所能表示的最多字符數就是2的8次方,也就是256。對于26個英文字母來說,大小寫全算上就是52個,再加上10個阿拉伯數字,62個字符,用可以表達256個不同字符的一個字節來存儲是足夠了。
但是,我們中國的常用漢字就有3000多個,用一個只能表達256個字符的字節顯然是不夠存儲的。至少也需要有2個字節,1個字節是8個二進制位,2個字節就是16個二進制位,最多可以表達2的16次方,也就是256*256=65536。65536個字符足夠容納所有中國的漢字,外帶日語、韓語、阿拉伯語、稀其古怪語等等各種各樣的字符。所以這樣就產生了Unicode,因為它用2字節表示字符,所以更嚴格來講應該叫UCS-2,后來因為怪字符太多,2字節都不夠用了,所以又搞出來了一個4字節表示的方法,稱作UCS-4。不過現在對絕大多數人來講UCS-2已經是足夠了。
Unicode本來是一個好東西,用2字節表示65536種字符,全人類皆大歡喜的事情。但是偏偏有一幫子西洋人,非要認為這個東西是一種浪費,說我們英文就最多只需要26個字母就夠了,1個字節就夠了,為什么要浪費2字節呢?比如說字母A就是0100 0001,這一個字節就夠了的東西,你弄2字節,非要在前面加8個0,0000 0000 0100 0001,這不是浪費嗎?我們就偏要用1字節表示英文。
好吧,我們全人類只好做妥協,規定每個字節,只要看見0打頭的,就知道這是英文字母,這肯定不是漢字,只有看見1開頭的,才認為這是漢字。
但是我們漢字用1個字節表示不下,那好辦,用2個1開頭的字符表示1個漢字。這樣本來16個二進制位,減去2個開頭的1,只剩下14個二進制位了,2的14次方就是16384個字符,對于中文來講,也是足夠用了。但是無奈他們還是想表達65536種字符,那怎么辦呢?就需要3個字節才能容納得下了,于是UTF-8粉墨登場。
首先,首位為0的字符被占了,只要遇到0開頭的字符,就知道這是一個1字節的字符,不必再往后數了,直接拿來用就可以,最多表示128種字符,從0000 0000到0111 1111,也就是從0到127。
接下來的事情就比較蹊蹺了。我們怎么用1開頭的字符既表示2字節,又表示3字節呢?假設我們只判斷首位的1,這顯然是不行的,沒有辦法區分,所以我們可以用10或者11開頭的字符來表示2字節,但是3字節又該以什么開頭?或者可以用10開頭表示2字節,用11開頭表示3字節?那么4字節的字符將來又該怎么辦?也許我們可以用110開頭表示3字節,用111開頭表示4字節?那么5字節6字節呢?似乎我們看到了一個規律:前面的1越多,代表字節數越多。
這時候,看一下我們的第一種方案:用10開頭表示2字節,那么我們的一個字符將是
10xx xxxx 10xx xxxx
用110表示3字節,那么一個3字節的字符將是:
110x xxxx 110x xxxx 110x xxxx
這樣無疑是能區分得開的。但是4字節怎么辦?
1110 xxxx 1110 xxxx 1110 xxxx 1110 xxxx
嗎?這樣也能區分開,但似乎有點浪費。因為每個字節的前半扇都被無用的位占滿了,真正有意義的只有后面一半。
或者我們干脆這樣做得了,我們來設計方案二:為了節省起見,所有后面的字符,我們統統都以10開頭,只要遇見10我們就知道它只是整個字符流的一部分,它肯定不是開頭,但是10這個開頭已經被我們剛剛方案一的2字節字符占用了,怎么辦?好辦,把2字節字符的開頭從10改成110,這樣它就肯定不會和10沖突了。于是2字節字符變成
110x xxxx 10xx xxxx
再往后順推,3字節字符變成
1110 xxxx 10xx xxxx 10xx xxxx
4字節字符變成
1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx
好像比剛才的方案一有所節省呢!并且還帶來了額外的好處:如果我沒有見到前面的110或者1110開頭的字節,而直接見到了10開頭的字節,毫無疑問地可以肯定我遇到的不是一個完整字符的開頭,我可以直接忽略這個錯誤的字節,而直接找下一個正確字符的開頭。
這個改良之后的方案二就是UTF-8!
UTF-8表示的字符數
現在,我們來算一下在UTF-8方案里,每一種字節可以表示多少種字符。
1字節的字符,以0開頭的,0xxx xxxx,后面7個有效位,2的7次方,最多可以表示128種字符。
2字節的字符,110x xxxx 10xx xxxx,數一數,11個x,所以是2的11次方,2的10次方是1024,11次方就是2048,很不幸,只能表示2048種字符,而我們的常用漢字就有3000多個,看來在這一區是放不下了,只好挪到3字節。
3字節的字符,1110 xxxx 10xx xxxx 10xx xxxx,數一數,16個x,2的16次方,最多可以表示65536個字符,所以我們的漢字就放在這一區,所以在UTF-8方案里我們的漢字都是以3個字節表示的。
所以這也就是這一張表的來歷:
UTF-16是Unicode字符編碼五層次模型的第三層:字符編碼表(Character Encoding Form,也稱為 "storage format")的一種實現方式。即把Unicode字符集的抽象碼位映射為16位長的整數(即碼元, 長度為2 Byte)的序列,用于數據存儲或傳遞。Unicode字符的碼位,需要1個或者2個16位長的碼元來表示,因此這是一個變長表示。
起初,UTF-16任何字符對應的數字都用兩個字節來保。但是,65536顯然是不算太多的數字,用它來表示常用的字符是沒一點問題,足夠了。但如果加上很多特殊的就也不夠了。于是,從1996年開始又來了第二個版本,用四個字節表示所有字符。這樣就出現了UTF-8,UTF16,UTF-32。UTF-32就是把所有的字符都用32bit也就是4個字節來表示。然后UTF-8,UTF-16就視情況而定了,UTF-16可以選擇兩字節或四字節。
UTF-16 并不是一個完美的選擇,它存在幾個方面的問題:
大小端轉換?
1、因為utf8是變長編碼,而且是單字節為編碼單元,不存在誰在高位、誰在低位的問題,所以不存在順序問題!順便說一下解碼,由于utf8的首字節記 錄了總字節數(比如3個),所以讀取首字節后,再讀取后續字節(2個),然后進行解碼,得到完整的字節數,從而保證解碼也是正確的。
2、utf16是變長編碼,使用1個16-bit編碼單元或者2個16-bit編碼單元,utf32是定長編碼,這里拿utf16舉例,在基本平面總是以2個字節為編碼單元, 鑒于“第一條”編碼單元與編碼單元之間的順序是正確的,問題只能在編碼單元內部中字節與字節的順序,由于硬件cpu的不同,編碼單元內部字節 與字節的順序不確定。假如cpu是大端序那么高位在前,如果cpu是小端序那么低位在前,為了區分,所以有了BOM(byte order mark),然后計 算機才能知道誰是高位,誰是低位,知道了高低位,從而能正確組裝,然后才能解碼正確。
例如,一個“奎”的Unicode編碼是594E,“乙”的Unicode編碼是4E59。如果我們收到UTF-16字節流“594E”,那么這是“奎”還是“乙”?如果BOM 是大端序,那么代碼點就應該是594E,那么就是“奎”,如果BOM是小端序,那么代碼點就應該是4E59,就是“乙”了。
綜上所述,因為utf8是單字節為編碼單元,在網絡傳輸時,不存在字節序列問題。在解碼時,由于首字節記錄了總字節數,所以能正確解碼。
因為utf16是定長編碼,總是以2個字節為編碼單元,在網絡傳輸時,不存在字節序列問題。在解碼時,由于cpu硬件差異,存在字節序問題,所以通 過BOM來標記字節順序;
另外,容錯性低有時候也是一大問題——局部的字節錯誤,特別是丟失或增加可能導致所有后續字符全部錯亂,錯亂后要想恢復,可能很簡單,也可能會 非常困難。(這一點在日常生活里大家感覺似乎無關緊要,但是在很多特殊環境下卻是巨大的缺陷)
目前支撐我們繼續使用 UTF-16 的理由主要是考慮到它是雙字節的,在計算字符串長度、執行索引操作時速度很快。當然這些優點 UTF-32 都具有,但很多人畢竟還是覺得 UTF-32 太占空間了。
UTF-8 也不完美,也存在一些問題:
UTF-8 的優點:
大神如何選擇的呢?
因為無論是 UTF-8 和 UTF-16/32 都各有優缺點,因此選擇的時候應當立足于實際的應用場景。例如在大神的習慣中,存儲在磁盤上或進行網絡交換時都會采用 UTF-8,而在程序內部進行處理時則轉換為 UTF-16/32。對于大多數簡單的程序來說,這樣做既可以保證信息交換時容易實現相互兼容,同時在內部處理時會比較簡單,性能也還算不錯。(基本上只要你的程序不是 I/O 密集型的都可以這么干,當然這只是大神粗淺的認識范圍內的經驗,很可能會被無情的反駁)
*請認真填寫需求信息,我們會在24小時內與您取得聯系。