js字符串

概述

定義

字符串就是零個或者多個排在一起的字符,放在單引號或者雙引號之中。

'abc'
"abc"

單引號字符串的內部,可以使用雙引號。雙引號的內部可以使用單引號。

'key = "value"'
"It's a long journey"

上面兩個都是合法字符串。

如果要在單引號字符串的內部,使用單引號(或者在雙引號的內部使用雙引號),就必須在內部的單引號(或者雙引號)前面加上反斜槓,用來轉義。

'Did she say \'hello\'?'
// "Did she say 'Hello'?"

"Did she say \"Hello\"?"
// "Did she say "Hello"?"

由於HTML語言的屬性值使用雙引號,所以很多項目約定JavaScript語言的字符串只使用單引號。

字符串默認只能寫在一行內,分成多行就會報錯。

'a
b
c'
// SyntaxError: Unexpected token ILLEGAL

上面代碼將一個字符串分成三行,JavaScript就會報錯。

如果字符串必須分成多行,可以在每一行的尾部使用反斜槓。

var longString = "Long \
long \
long \
string"
// "Long long long string"

上面代碼表示,加了反斜槓以後,原來寫在一行的字符串,可以分成多行書寫。但是,輸出的時候還是單行,效果與寫在同一行完全一樣。注意反斜槓後面必須是換行符,而不能有其他字符(比如空格),否則會報錯。

連接運算符(+)可以連接多個字符串,將長字符串拆成多行書寫,輸出的時候也是單行。

var longString = 'Long '
  + 'long '
  + 'long '
  + 'string';

如果想輸出多行字符串,有一種利用多行註釋的變通方法。

(function () { /*
line 1
line 2
line 3
*/}).toString().split('\n').slice(1, -1).join('\n')
// "line 1
// line 2
// line 3"

上面的例子中,輸出的字符串就會多行。

轉義

反斜槓()在字符串內有特殊含義,用來表示一些特殊的字符,所以又稱爲轉義字符。

需要用反斜槓轉義的特殊字符,主要有一下這些:

\0 null(\u0000)
\b 後退鍵(\u0008)
\f 換頁符(\u000C)
\n 換行符(\u000A)
\r 回車鍵(\u000D)
\t 製表符(\u0009)
\v 垂直製表符(\u000B)
\’ 單引號(\u0027)
\” 雙引號(\u0022)
\反斜槓(\u005C)

上面這些字符前面加上反斜槓,都表示特殊含義。

console.log('1\n2')
//1
//2

上面代碼中,\n表示換行,輸出的時候就分成了兩行。

反斜槓還有三種特殊的用法。

(1)\HHH

反斜槓後面緊跟三個八進制數(000到377),代表一個字符。HHH對應該字符的Unicode碼點,比如\251表示版權符號。顯然,這種方法只能輸出256中字符。

(2)\xHH

\x後面緊跟兩個十六進制數(00到FF),代表一個字符。HH對應該字符的Unicode碼點,比如\xA9表示版權符號。這種方法也只能輸出256種字符。

(3) \uXXXX

\u後面緊跟四個十六進制數(0000到FFFF),代表一個字符。HHHH對應該字符的Unicode碼點,比如\u00A9表示版權符號。

下面這是三種字符特殊寫法的例子。

'\251' // "©"
'\xA9' // "©"
'\u00A9' // "©"

'\172' === 'z' // true
'\x7A' === 'z' // true
'\u007A' === 'z' // true

如果在非特殊字符前面使用反斜槓,則反斜槓會被省略。

'\a'
// "a"

上面代碼中,a是一個正常字符,前面加反斜槓沒有特殊含義,反斜槓會被自動省略。

如果字符串的正常內容之中,需要包含反斜槓,則反斜槓前面需要再加一個反斜槓,用來對自身轉義。

"Prev \\ Next"
// "Prev \ Next"

字符串與數組

字符串可以被視爲字符串數組,因此可以使用數組的方括號運算符,用來返回某個位置的字符(位置編號從0開始)。

var s = 'hello';
s[0] // "h"
s[1] // "e"
s[4] // "o"

//直接對字符串使用方括號運算符
'hello'[1] // "e"

如果方括號中的數組超過字符串的長度,或者方括號中根本不是數字,則返回unefined。

'abc'[3] // undefined
'abc'[-1] //undefined
'abc'.['x'] //undefined

但是,字符串與數組的相似性僅此而已。實際上,無法改變字符串之中的額單個字符。

var s = 'hello';
delete s[0];
s //"hello"

s[1] = 'a';
s //"hello"

s[5] = '!'
s //"hello"

上面代碼表示,字符串內部單個字符無法改變赫爾增刪,這些操作會陌陌失敗。

字符串也無法直接使用數組的方法,必須通過call方法簡介使用。

var s = 'hello';
s.join(' ') / TypeError: s.join is not a function
Array.prototype.join.call(s,' ') // "h e l l o"

上面代碼中,如果直接對字符串使用數組的join方法,就會報錯不存在該方法。但是,可以通過call方法,間接對字符串使用join方法。

不過,由於字符串是隻讀的,那些會改變原數組的方法,比如push()、sort()、reverse()、splice()都對字符串無效,只有將字符串顯式地轉爲數組後才能使用。

length屬性

length屬性返回字符串的長度,該屬性也是無法改變的。

var s = 'hello';
s.lengh // 5

s.length = 3;
s.length // 5

s.length = 7
s.length //5

上面代碼表示字符串的length屬性無法改變,但是不會報錯。

字符集

JavaScript使用Unicode字符集。也就是說,在JavaScript引擎內部,所有字符都用Unicode表示。

JavaScript不僅以Unicode存儲字符,還允許直接在程序中使用Unicode編號表示字符,即字符寫成\uxxxx形式,其中xxxx表示該字符Unicode編碼。比如,\u00A9代表版權符號。

var s = '\u00A9';
s //"©"

解析代碼的時候,第一行變量名foo是Unicode形式表示,第二行是字面形式表示。JavaScript會自動識別。

我們還需要知道,每個字符在JavaScript內部都是以16位(即兩個字節)的UTF-16格式存儲。也就是說,JavaScript的單位字符長度固定爲16位字符,即2個字節。

但是,UTF-16有兩種長度:對於U+0000到U+FFFF之間的字符,長度爲16位(即2個字節);對於U+10000到U+10FFFF之間的字符,長度爲32位(即4個字節)而且前兩個字節在0xD800到0xDBFF之間,後兩個字節在0xDC00到0xDFFF之間。舉例來說,U+1D306對應的字符爲��,它寫成UTF-16就是0xD834 0xDF06。瀏覽器會正確將這四個字節識別爲一個字符,但是JavaScript內部的字符長度總是固定爲16位,會把這四個字節視爲兩個字符。

var s = '\uD834\uDF06';

s // "��"
s.length // 2
/^.$/.test(s) // false
s.charAt(0) // ""
s.charAt(1) // ""
s.charCodeAt(0) // 55348
s.charCodeAt(1) // 57094

上面代碼說明,對於於U+10000到U+10FFFF之間的字符,JavaScript總是視爲兩個字符(字符的length屬性爲2),用來匹配單個字符的正則表達式會失敗(JavaScript認爲這裏不止一個字符),charAt方法無法返回單個字符,charCodeAt方法返回每個字節對應的十進制值。

所以處理的時候,必須把這一點考慮在內。對於4個字節的Unicode字符,假定C是字符的Unicode編號,H是前兩個字節,L是後兩個字節,則它們之間的換算關係如下。

// 將大於U+FFFF的字符,從Unicode轉爲UTF-16
H = Math.floor((C - 0x10000) / 0x400) + 0xD800
L = (C - 0x10000) % 0x400 + 0xDC00

// 將大於U+FFFF的字符,從UTF-16轉爲Unicode
C = (H - 0xD800) * 0x400 + L - 0xDC00 + 0x10000

下面的正則表達式可以識別所有UTF-16字符。

([\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF])

由於JavaScript引擎(嚴格說是ES5規格)不能自動識別輔助平面(編號大於0xFFFF)的Unicode字符,導致所有字符串處理函數遇到這類字符,都會產生錯誤的結果(詳見《標準庫》一章的String對象章節)。如果要完成字符串相關操作,就必須判斷字符是否落在0xD800到0xDFFF這個區間。

下面是能夠正確處理字符串遍歷的函數。

function getSymbols(string) {
  var length = string.length;
  var index = -1;
  var output = [];
  var character;
  var charCode;
  while (++index < length) {
    character = string.charAt(index);
    charCode = character.charCodeAt(0);
    if (charCode >= 0xD800 && charCode <= 0xDBFF) {
      output.push(character + string.charAt(++index));
    } else {
      output.push(character);
    }
  }
  return output;
}

var symbols = getSymbols('��');

symbols.forEach(function(symbol) {
  // ...
});

替換(String.prototype.replace)、截取子字符串(String.prototype.substring, String.prototype.slice)等其他字符串操作,都必須做類似的處理。

Base64轉碼

Base64是一種編碼方法,可以將任意字符轉成可打印字符。使用這種編碼方法,主要不是爲了加密,而是爲了不出現特殊字符,簡化程序的處理。

JavaScript原生提供兩個Base64相關方法。

btoa():字符串或二進制值轉爲Base64編碼
atob():Base64編碼轉爲原來的編碼

var string = 'Hello World!';
btoa(string) // "SGVsbG8gV29ybGQh"
atob('SGVsbG8gV29ybGQh') // "Hello World!"

這兩個方法不適合非ASCII碼的字符,會報錯。

btoa('你好')
// Uncaught DOMException: The string to be encoded contains characters outside of the Latin1 range.

要將非ASCII碼字符轉爲Base64編碼,必須中間插入一個轉碼環節,再使用這兩個方法。

function b64Encode(str) {
  return btoa(encodeURIComponent(str));
}

function b64Decode(str) {
  return decodeURIComponent(atob(str));
}

b64Encode('你好') // "JUU0JUJEJUEwJUU1JUE1JUJE"
b64Decode('JUU0JUJEJUEwJUU1JUE1JUJE') // "你好"

摘自 http://javascript.ruanyifeng.com

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章