官术网_书友最值得收藏!

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ū)別。
主站蜘蛛池模板: 太保市| 翁牛特旗| 滨海县| 甘泉县| 手机| 上高县| 开平市| 湘阴县| 措勤县| 平安县| 巴南区| 青冈县| 乃东县| 通海县| 永和县| 灵川县| 凤台县| 曲水县| 漠河县| 康乐县| 长泰县| 金寨县| 惠州市| 永仁县| 海晏县| 洪雅县| 济源市| 华安县| 余庆县| 旺苍县| 平和县| 曲沃县| 龙里县| 田东县| 铁岭市| 革吉县| 辽源市| 双城市| 隆德县| 凤台县| 社会|