- JS全書:JavaScript Web前端開發(fā)指南
- 高鵬
- 3993字
- 2020-09-18 10:29:16
3.4 字符串
字符串可以由單引號(')或雙引號(")或反撇號(`)直接包裹0個或多個字符組成,像這樣的方式直接標識一個字符串也稱為字符串字面量表示法,除此之外,還可以通過構(gòu)造函數(shù)String來創(chuàng)建一個字符串。
在上一節(jié)中,我們已經(jīng)知道,這兩種方式創(chuàng)建的字符串除了類型不同,其值相等,且擁有相同的屬性和方法。在日常使用中區(qū)別不大,一般情況下,建議使用字符串的字面量表示法,這樣更方便,示例如下。
let foo = 'string'; let bar = "string"; let baz = `string`; let qux = new String('string');
但需要注意的是,以何種引號/反撇號開頭就必須以相同的引號/反撇號結(jié)尾,像下面這樣的使用方式將會報錯。
//以下是錯誤的使用方式
let foo = 'string";
let bar = 'string`;
let baz = `string";
let qux = new String('string');
如果字符串中含有具有特殊功能的字符串,就需要使用轉(zhuǎn)義字符進行轉(zhuǎn)義。轉(zhuǎn)義字符由一個反斜杠和一個或多個字符組成,表3-2列舉了一些常見的轉(zhuǎn)義字符。
表3-2 轉(zhuǎn)義字符

例如,下面的代碼就會造成歧義與報錯。
let foo = 'stri'ng'; // ->報錯
這時就需要用到轉(zhuǎn)義字符:
let foo = 'stri\'ng';
在字符串字面量表示法中,單引號和雙引號的使用方法相同,反撇號為ES6中新引入的一種字符串字面量語法,可以用它來代替單引號和雙引號。在JavaScript中,反撇號又被稱為“模板字符串”(template strings)。
在模板字符串中,可以包含特定的表達式占位符,JavaScript會解析這些表達式占位符并返回解析后的字符串,示例如下。
let foo = 'hello';
let bar = `${foo} world`;
console.log(bar); // > "hello world"
這里的表達式不僅只能是一個變量,也可以是其他JavaScript語句,示例如下。
//可以進行運算 `${1+1} = ${2}`; // -> "2 = 2"
//可以是一個函數(shù) `${foo()}`;
...
為什么需要模板字符串呢?隨著Web的應用化,JavaScript需要做的事也越來越多,拼接字符串更是在代碼中隨處可見,示例如下。

普通字符串無法表示多行字符串,因此需要使用加號連接符進行連接,上面的寫法使用了大量的加號連接字符串,這就導致代碼閱讀起來并不是很直觀,尤其是在處理大量復雜數(shù)據(jù)的情況下,這種寫法很容易導致代碼出現(xiàn)問題(寫代碼時基本是沒有問題的,但當接手別人的項目或維護自己很久之前寫的代碼時,這種寫法就顯得比較亂,對這類代碼進行修改時也容易出現(xiàn)問題)。
模板字符串正是在這樣的環(huán)境下產(chǎn)生的,使用模板字符串可以很好地解決上面的問題,示例如下。

這樣,我們的代碼看起來就很清晰了,但要注意的是,模板字符串會保留其中的空格、換行符、制表符等。因此,在上面的代碼中,就多出了一些空格和換行符,我們可以使用trim()方法來去除這些多余的字符。
3.4.1 字符串的特點
字符串是不可變的,即一旦字符串被創(chuàng)建,該字符串的值就不能改變了,如果要改變一個變量中包含的字符串的值,需要用另一個字符串賦值給該變量,原來的字符串將會被銷毀。
這個過程與上一節(jié)中的基本包裝類型類似,示例如下。
let foo = "hello";
foo = "world";
console.log(foo); // > "world";
上述代碼可以看作是執(zhí)行了類似下面的操作。
let foo = "hello";
foo = new String("world"); // 銷毀 "hello"、 銷毀 "world"
console.log(foo); // > "world"
上述代碼中,對變量foo賦值時,實際上是創(chuàng)建了一個新的字符串,并將該字符串的值賦值給變量foo,并不是直接將"hello"的值修改為"world",而在變量foo的值發(fā)生改變后,"hello"不再被使用,將會被直接銷毀。
為了進一步驗證上面的結(jié)果,我們直接修改原字符串的值。
同樣,下面的示例中,"hello world"是以"hello"和" world"創(chuàng)建的兩個新字符串的值連接后返回的結(jié)果。
let foo = "hello" + " world";
// foo = new String("world") + new String(" world");
console.log(foo); // > "hello world"
3.4.2 length屬性
length是一個屬性,而不是一個方法,length屬性返回字符串的長度,示例如下。
'string'.length; // -> 5
如果字符串中包含轉(zhuǎn)義字符,每個轉(zhuǎn)義字符會被解析成一個字符,示例如下。

3.4.3 實例方法
JavaScript提供了一些方法用來對字符串進行操作,這些方法看起來很多,但實際上很多方法都是類似的。
這些方法不會修改字符串本身,而是返回一個新的字符串或其他值。
1. str.charAt([index])和str.charCodeAt([index])
str.charAt([index])和str.charCodeAt([index])這兩個方法用來對字符串中指定索引處的字符進行取值,并將所取得的值返回。其中,charAt()方法取的是字符串中指定索引index處的字符,而charCodeAt()方法取的是該字符的Unicode碼點。
索引index的取值區(qū)間為[0,length-1]的數(shù)字(length為字符串的長度),如果索引不是數(shù)字,將會隱式轉(zhuǎn)換成一個數(shù)字,默認為0,示例如下。

在JavaScript中,索引是從0開始的,因此取索引為0處的字符,取得就是第一個字符。
如果索引的值不是整數(shù),這兩個方法都會將該值進行去尾操作,并使用去尾后的數(shù)值作為索引,示例代碼如下。
let foo = "hello world";
// 非整數(shù)索引取字符 foo.charAt(0.9); // -> "h"
// 非整數(shù)索引取字符的 `Unicode` 碼點 foo.charCodeAt(0.9); // -> 104
對于索引不在區(qū)間內(nèi)的,charAt()方法將會返回一個空字符串,而charCodeAt()則是返回NaN,示例如下。
let foo = "hello world";
// 取字符 foo.charAt(-1); // -> ""
// 取字符的 `Unicode` 碼點 foo.charCodeAt(-1); // -> NaN
不過,一般情況下很少使用charAt()方法,因為還有另外一種更便捷的方式可以獲取指定索引出的字符,示例如下。
foo[0]; // -> "h"
// 這種方式不會對索引值進行類型轉(zhuǎn)換,也不會執(zhí)行去尾操作 foo[0.9]; // -> undefined foo[null]; // -> undefined foo[-1]; // -> undefined
2. str.codePointAt(index)
在JavaScript內(nèi)部,字符是以UTF-16的格式存儲的,每個字符占用2個字節(jié),但有些字符可能會占用4個字節(jié)(兩個UTF-16,又稱UTF-32),charCodeAt()方法不能正確處理這些需要占用4個字節(jié)的字符,codePointAt()方法正是為了解決這個問題而出現(xiàn)的。
這個方法與charCodeAt()方法類似,同樣是返回指定索引處字符的碼點,但不同之處在于,codePointAt()方法的返回值如下。
- 如果該索引處沒有字符,則返回undefined。
- 如果該字符占用4個字節(jié),則返回該字符的UTF-32的碼點。
- 如果該字符占用2個字節(jié),則返回該字符的UTF-16的碼點。
示例如下。

3. str.concat(str1[,…, strN])
concat()方法把一個或多個字符串與str連接,并返回一個新的字符串,示例如下。
"hello".concat(" world"); // -> "hello world"
不過,我們一般用+運算符來代替這個方法,示例如下。
"hello" + " world"; // -> "hello world"
4. str.indexOf(searchString[, fromIndex])和str.lastIndexOf(searchString[, fromIndex])
str.indexOf(searchString[, fromIndex])和str.lastIndexOf(searchString[, fromIndex])這兩個方法用來查詢給定的字符串searchString在str中首次出現(xiàn)的位置,如果沒有找到,就返回-1,fromIndex為可選參數(shù),表示從何處開始(包含這個位置)查詢。
在indexOf()中,fromIndex默認為0,如果fromIndex小于0,也會被當作0處理,示例如下。

上述代碼中,不指定fromIndex,或指定fromIndex小于等于0,表示的是從字符串的起始位置開始往后查詢,遇到的第一個"o"的索引為4,因此返回4;當指定fromIndex為5時,將從字符串的索引位置為5的位置(空字符)開始往后查詢,直到遇到第一個"o"的索引為7,返回索引7。
當fromIndex的值超出字符串的最大索引,即fromIndex的值大于等于字符串的長度時,將會返回-1。通過前文我們已經(jīng)知道,對于索引不在區(qū)間內(nèi)的,charAt()方法將會返回一個空字符串,也就是說,可以看作是超出字符串長度的是全都是空字符串,如果要查找的字符串不為空,那么,在超出最大索引的位置外就找不到匹配的字符,因此返回-1。
示例代碼如下。

lastIndexOf()方法與indexOf()方法類似,只不過查詢方式與indexOf()相反,是從后向前查找的。
在lastIndexOf()中,fromIndex默認為字符串的最大索引值(以下簡稱str.length-1),如果fromIndex大于最大索引值,也會被當作最大索引值處理,示例如下。

當fromIndex的值小于等于0時,示例如下。

可以用這兩個方法判斷一個字符串是否包含另一個字符串,示例如下。
let foo = "hello world";
if(foo.indexOf('hello') !== -1){ // ... }
5. str.includes(searchString[, fromIndex])、str.startsWith(searchString [, fromIndex])和str.ends With(searchString [, fromIndex])
ES6中新增了3種方法來判斷一個字符串是否被另一個字符串包含(此前,只能通過對lastIndexOf()與indexOf()返回的索引值進行判斷來判斷),如果被包含,則返回true,否則,返回false。
fromIndex為可選參數(shù),表示從何處開始查詢,默認為0,示例如下。

endsWith()方法與lastIndexOf()類似,也是從后向前查找的,但endsWith()是從fromIndex()之后(不包含當前指定的索引位置)開始查詢的,示例如下。

6. str.search(regexp)
str.search(regexp)方法與indexOf()相同,返回匹配到的字符串在str中首次出現(xiàn)的位置,如果沒有找到,則返回-1,只不過search()方法接收一個正則表達式作為參數(shù)(非正則表達式會被轉(zhuǎn)換為正則表達式處理),示例如下。
"hello world".search(/l/); // -> 2 "hello world".search(/a/); // -> -1
// 非正則表達式轉(zhuǎn)為正則表達式處理 "hello world".search("l"); // -> 2 "hello world".search("a"); // -> -1
7. str.localeCompare(compareStr)
localeCompare()方法用來比較兩個字符串,如果str小于compareStr,則返回負值,如果str等于compareStr,則返回0,如果str大于compareStr,則返回正值,示例如下。
// Chrome 59 "a".localeCompare("b"); // -> -1 "a".localeCompare("a"); // -> 0 "b".localeCompare("a"); // -> -1
8. str.padStart(targetLength [, char])和str.padEnd(targetLength [, char])
ES8中引入了padStart()和padEnd()兩個方法用來補全字符串,targetLength為補全后字符串的長度,這兩個方法的返回值都是補全后的字符串。
char為可選參數(shù),表示用來補全字符串的字符,默認為空格,示例如下。

如果targetLength小于當前字符串的長度,則返回當前字符串,示例如下。

9. str.repeat([count])
repeat()方法將重復count次后的str連接后返回。
count為可選參數(shù),表示重復的次數(shù),取值區(qū)間為[0, Infinity),默認為0,傳入?yún)^(qū)間外的值,會拋出錯誤RangeError,示例如下。

10. str.replace(oldValue, newValue)
replace()方法將str中的oldValue替換為newValue。
oldValue可以是一個字符串或正則表達式,具體如下。
- oldValue為字符串時,將匹配到的第一個oldValue替換為newValue。
- oldValue為正則表達式時,將匹配到的oldValue替換為newValue。
示例如下。

newValue表示用來替換oldValue的新值,newValue可以是一個字符串或函數(shù),具體如下。
- newValue為字符串時,該字符串內(nèi)可插入一些具有特殊含義的字符。
- newValue為函數(shù)時,函數(shù)的返回值將被作為替換字符串處理。
示例如下。

此外,newValue中還有一些特殊的字符表示匹配的結(jié)果,如表3-3所示。
表3-3 特殊字符

示例如下。

11. str.slice(startIndex[, endIndex])和str.substring(startIndex[, endIndex])
slice()方法從str中截取一段字符串,并將其返回。startIndex表示從何處開始截取,默認為0;endIndex為可選參數(shù),表示截取到何處(不包含endIndex),默認為字符串的長度,示例如下。

substring()方法與slice()方法類似,示例如下。

不同之處在于,slice()的參數(shù)為負值時,會被當作參數(shù)index+字符串長度length處理,示例如下。

substring()則將負值當作0處理,示例如下。
"hello world".substring(-1); // -> "hello world"
如果不知道某個字符串的索引,那么此時就需要用到前面所學的indexOf()和lastIndexOf(),或者search()方法。
12. str.substr(startIndex[, subLength])
substr()方法與slice類似,也是從str中截取一段字符串,并將其返回。fromIndex可以為負值,只不過substr()的subLength表示的是截取的字符串的字符個數(shù),默認截取到字符串的末尾,示例如下。

13. str.split([separator[, limit]])
split()方法將字符串用分隔符separator分割成數(shù)組,并將其返回。limit為可選參數(shù),表示返回的數(shù)組長度,limit為負值時會被忽略。
分隔符separator支持正則表達式,示例如下:

14. str.toLocaleLowerCase()、str.toLocaleUpperCase()、str.toLowerCase()和str.toUpperCase()
這四個方法可以將字符串中的字母(以下簡稱“特定字符”)進行大小寫轉(zhuǎn)化,并返回轉(zhuǎn)化后的字符串,具體如下。
- toLocaleLowerCase使用本地化的規(guī)則將特定字符轉(zhuǎn)化為小寫。
- toLocaleUpperCase使用本地化的規(guī)則將特定字符轉(zhuǎn)化為大寫。
- toLowerCase將特定字符轉(zhuǎn)化為小寫。
- toUpperCase將特定字符轉(zhuǎn)化為大寫。
示例如下。

15. str.trim()、str.trimLeft()和str.trimRight()
這三個方法去除字符串左右兩邊的空格,并返回新的字符串,具體如下。
- trim:去除字符串兩邊的空格。
- trimLeft:去除字符串左邊的空格。
- trimRight:去除字符串右邊的空格。
示例如下。

練習
- 創(chuàng)建一個字符串,在其上調(diào)用不同的字符串方法,并對比調(diào)用方法后返回值與原字符串的區(qū)別。
- 從零開始:數(shù)字圖像處理的編程基礎與應用
- Magento 2 Theme Design(Second Edition)
- Java應用開發(fā)技術(shù)實例教程
- Oracle從入門到精通(第5版)
- H5頁面設計:Mugeda版(微課版)
- C語言程序設計教程
- Statistical Application Development with R and Python(Second Edition)
- MATLAB GUI純代碼編寫從入門到實戰(zhàn)
- Clojure for Java Developers
- FFmpeg開發(fā)實戰(zhàn):從零基礎到短視頻上線
- 計算機應用技能實訓教程
- 交互式程序設計(第2版)
- Java程序設計教程
- Java設計模式深入研究
- Python Penetration Testing Essentials