JavaScript 引用類型之原始值包裝類型String

String 原始值包裝類型

String是對應字符串的引用類型。要創建一個String 對象,使用String 構造函數並傳入一個數值。

let  stringObject = new String("hello world");

String 對象的方法可以在所有字符串原始值上調用。3個繼承的方法valueOf,toLocalString()和String()都返回對象的原始字符串值。 每個String對象都有一個length屬性,表示字符串中字符的數量。

let stringValue = "hello world";
console.log(stringValue.length);// "11"

String 類型提供瞭很多方法來解析和操作字符串。比如字符串截取函數,slice(),substr(),substring(),字符串連接函數concat(),查詢字符串位置相關函數, indexOf(),lastIndexOf(),字符串大小寫轉換函數toLowerCase(),toLocalLowerCase(),toUpperCase(),toLocalUpperCase()等等,本文將對幾乎所有的字符串方法進行總結梳理,以便後用。

String 原始值包裝類型 操作方法

1.字符串編碼常規化函數 normalize()方法

某些Unicode 字符可以有很多種編碼方式。有的字符可以通過一個BMP字符表示,也可以通過一個代理對表示。

//U+00C5 上面帶圓圈的大寫拉丁字母A
console.log(String.fromCharCode(0x00C5)); //Å

//U+212B:長度單位 “埃”
console.log(String.fromCharCode(0x212B));// Å

//U+004 大寫拉丁字母A
//U+030A: 上面加個圓圈
console.log(String.fromCharCode(0x0041,0x030A)); // Å

比較操作符不在於字符開起來是什麼樣的,因此著三個字符互不相等。

let a1 = String.fromCharCode(0x00C5),
a2 = String.fromCharCode(0x212B),
a3 = String.fromCharCode(0x0041,0x030A);

console.log(a1,a2,a3); // Å,Å,Å

console.log(a1 === a2);//false
console.log(a2 === a3);//false
console.log(a1 === a3);//false

為解決這個問題,Unicode 提供瞭4種規范化形式, 可以將上面的字符規范化為一致的格式,無論底層字符的代碼是什麼。這4種規范化形式是:NFD,NFC,NFKD和NFKC。可以使用normalize()方法對字符串應用上述規范化形式,使用時需要穿入表示哪種形式的字符串:"NFD","NFC","NFKD","NFKC";

通過比較字符串與其調用normalize()的返回值,就可以知道該字符串是否已經規范化瞭:

let a1 = String.fromCharCode(0x00C5),
a2 = String.fromCharCode(0x212B),
a3 = String.fromCharCode(0x0041,0x030A);

// U+00C5 是對0+212B 進行NFC/NFKC 規范化之後的結果
console.log(a1 === a1.normalize("NFD")); // false
console.log(a1 === a1.normalize("NFC"));//true
console.log(a1 === a1.normalize("NFKD"));// false
console.log(a1 === a1.normalize("NFKC"));//true

//U+212B 是未規范化的
console.log(a2 === a2.normalize("NFD")); // false
console.log(a2 === a2.normalize("NFC"));//false
console.log(a2 === a2.normalize("NFKD"));// false
console.log(a2 === a2.normalize("NFKC"));//false

//U+0041/U+030A 是對0+212B 進行NFD/NFKD 規范化之後的結果
console.log(a3 === a3.normalize("NFD")); // true
console.log(a3 === a3.normalize("NFC"));//false
console.log(a3 === a3.normalize("NFKD"));// true
console.log(a3 === a3.normalize("NFKC"));//false

選擇同一種規范化形式可以讓比較操作符返回正確的結果:

let a1 = String.fromCharCode(0x00C5),
a2 = String.fromCharCode(0x212B),
a3 = String.fromCharCode(0x0041,0x030A);

console.log(a1.normalize("NFD") === a1.normalize("NFD")); // false
console.log(a2.normalize("NFKC") === a2.normalize("NFKC"));//false
console.log(a3.normalize("NFC") === a3.normalize("NFC"));// false

2.字符串拼接函數concat()

concat()用於將一個或多個字符串拼接成一個新字符串。

let stringValue = "hello";
let result = stringValue.concat("world");

console.log(result);// hello world
console.log(stringValue);// hello 

stringValue 調用concat()方法返回的結果是得到"hello world" ,但stringValue 的值保持不變
concat()方法可以接受任意多個參數,因此可以一次性拼接多個字符串

let stringValue = "hello ";
let result = stringValue.concat("world","!");

console.log(result);// "hello world!"
console.log(stringValue); // "hello "

3.字符串提取子字符串方法:slice(),substr(),substring()

slice(),substr(),substring() 這三個方法都返回它們的字符串的一個子字符串,而且都接收一個或兩個參數。

第一個參數表示子字符串開始的位置,第二個參數表示子字符串結束的位置。

對slice()和substring()而言,第二個參數是提取結束的位置(即該位置之前的字符會被提取出來)。

對substr()而言,第二個參數表示返回的子字符串的字符數量。

任何位情況下,省略第二個參數都意味著提取到字符串末尾。

與concat()方法一樣,slice(),substr()和substring()也不會修改調用它們的字符串。

let stringValue = "hello world";
// 傳遞一個參數,相當於提取到字符串末尾
console.log(stringValue.slice(3));        //"lo world"
console.log(stringValue.substr(3));       //"lo world"
console.log(stringValue.substring(3);     //"lo world"

// 傳遞2個參數,slice(),substring()結果一致,substr() 結果與前兩者有區別
console.log(stringValue.slice(3,7));        //"lo w"
console.log(stringValue.substr(3,7));       //"lo w"
console.log(stringValue.substring(3,7);     //"lo worl"

當傳遞給slice(),substring(),substr的參數為負數時,這三個函數的行為有所不同。 slice()方法將所有負數參數都當成字符串長度加上參數值。

substring()方法將所有負參數值都轉換為0.

substr()方法將第一個負參數值當成字符串長度加上該值,將第二個負參數值轉換為0.

let stringValue = "hello world";
console.log(stringValue.slice(-3));// "rld"
console.log(stringValue.substring(-3));//"hello world"
console.log(stringValue.subst(-3));//"rld"

console.log(stringValue.slice(3,-4));// "lo w" 轉化為 (3,-4 + 11) = (3,7)
console.log(stringValue.substring(3,-4));//"hel",轉化為(3,0),這個函數會將較小的參數作為起點,較大的參數作為終點,所以相當於(0,3) 
console.log(stringValue.substr(3,-4));//"" 轉化為(3,0)

4.字符串位置方法 indexOf(),lastIndexOf()

有兩個方法用於在字符串中定位子字符串,indexOf()和lastIndexOf().這兩個方法在字符串中搜索傳入的字符串,並返回位置(如果沒找到,則返回-1.).

兩者的區別在於,indexOf()從字符串開頭開始查找子子字符串,而lastIndexOf()方法從公字符串末尾開始查找子字符串。

let stringValue = "hello world";
console.log(stringValue.indexOf("o");//4
console.log(stringValue.lastIndexOf("o"));// 7 

這兩個方法都可以接收第二個參數,表示開始搜索的位置。這意味著,indexOf()會從這個參數指定的位置開始向字符串末尾搜索,忽略位置之前的字符;lastIndexOf()則會從這個參數指定的位置開始向字符串開頭開始搜索,忽略該位置之後直到字符串末尾的字符。

需要註意的是,返回值的位置永遠是搜索的子字符串在搜索字符串中的正序位置,不會因為第二個參數而改變。並且傳入的搜索的范圍包含第二個參數傳遞的位置。

let stringValue = "hello world";
console.log(stringValue.indexOf("o",7));// 7
console.log(stringValue.lastIndexOf("o",7));//7

5.字符串包含方法:startsWith(),endsWith()和includes()

ECMAScript 6 增加瞭3個用於判斷字符串是否包含另一個字符串的方法:startsWith(),endsWith()和includes().這些方法都會從字符串中搜素傳入的字符串,並返回一個是否包含的佈爾值。
區別在於,startsWith()檢查開始於索引0的匹配項,endsWith()檢查開始於索引(string.length – substring.length())的匹配項,而includes()檢查整個字符串

let message = "foobarbaz";

console.log(message.startsWith("foo"));//true
console.log(message.endsWith("bar"));//false

console.log(message.endsWith("baz"));//true
console.log(message.startsWith("bar"));//false

console.log(message.includes("foo"));//true
console.log(message.includes("qux"));//false

startsWith()和incluedes()方法接收可選的第二個參數,表示開始搜索的位置。如果傳入第二個參數,則意味著這兩個方法會從指定位置向著字符串末尾搜索,忽略位置之前的所有字符。

let message = "foobarbaz";

console.log(message.startsWith("foo"));//true
console.log(message.startsWith("foo",1));//false

console.log(message.includes("bar"));//true
console.log(message.includes("bar",4));//false

endsWith()方法接收可選的第二個參數,表示把傳入的第二個參數作為字符串結尾的位置。如果不提供這個參數,那麼默認就是字符串長度。如果提供瞭這個參數,那麼就好像字符串直郵那麼差多字符一樣。

let message = "foobarbaz";

console.log(message.endsWith("bar"));//false
console.log(message.endsWith("bar",6));//true

6.去除字符串前後空格的方法 trim(),trimLeft(),trimRight()

ECMAScript 在所有字符串上提供瞭trim()方法。這個方法會創建字符串的一個副本,刪除前後的所有空格,在返回結果。 trimLeft()和trimRight()方法分別從字符串開始和末尾清理空格符。

let stringValue = "  hello world  ";
let trimmedStringValue = stringValue.trim();
console.log(stringValue); // "  hello world  "
console.log(trimmedStringValue);//"hello world"
console.log(stringValue.trimLeft());//"hello world " 
console.log(stringValue,trimRight());//"  hello world"

7.字符串的重復復制 repeat()

ECMAScript 在所有字符串上都提供瞭repeat()方法。這個方法接收一個整數參數,表示要將字符串復制多少次,然後返回拼接所有副本後的結果。

let stringValue = "na ";
console.log(stringValue.repeat(3) + "batman"); // na na na batman

8.字符串填充函數 padStart() 和 padEnd()方法

padStart() 方法和padEnd()方法會復制字符串,如果小於指定長度,則在相應一邊填充字符,直至滿足長度條件。這兩個方法的第一個參數是長度,第二個參數是可選的填充字符串,默認為空字符串(U+0020).

let stringValue = "foo";

console.log(stringValue.padStart(6)); // "   foo"
console.log(stringValue.padStart(9,"."));// "......foo"

console.log(stringValue.padEnd(6));//"foo   ";
console.log(stringValue.padEnd(9,"."));//"foo......"

可選的第二個參數並不局限於一個字符。如果提供瞭多個字符的字符串,則會將其拼接並截斷以匹配指定長度。此外,如果長度小於或等於字符串長度,則會返回原始字符串。

傳入的第二個參數表示的是字符串的總長度

let stringValue = "foo";
console.log(stringValue.padStart(8,"bar"));//"barbafoo"

console.log(stringValue.padEnd(8,"bar"));//"foobarba"
console.log(stringValue.padEnd(2));// "foo"

9.字符串迭代與 解構

字符串的原型上暴露瞭一個@@iterator 方法,表示可以迭代字符串的每個字符。 可以手動調用迭代器

let message = "abc";
let stringIterator = message[Symbol.iteator]();

console.log(stringIterator.next());// {value:"a",done:false}
console.log(stringIterator.next());//{value:"b",done:false}
console.log(stringIterator.next());//{value:"c",done:false}
console.log(stringIterator.next());//{value:undefiend,done:true}

在for 循環中可以通過這個迭代器按序訪問每個字符:

for (const c of "abc") {
    console.log(c);
}
// a
//b
//c

有瞭這個迭代器之後,字符串就可以通過結構操作符來解構瞭。比如,可以方便的把字符串分割為數組:

let message = "abcde";
console.log([...message]);// ["a","b","c","d","e"]

10.字符串大小寫轉換

字符串大小寫轉換函數涉及4個方法:toLowerCase(),toLocaleLowerCase(),toUpper()和toLocale UpperCase().toLowerCase()和toUpperCase()方法是原來就有的 方法,與java.lang.String 中的方法同名。toLocaleLowerCase()和toLocaleUpperCase()方法旨在基於特定地區實現。在很多地區,地區的方法與通用的方法是一樣的。但在少數語言中(如土耳其語),Unicode大小寫轉換需應用特殊規則,要使用地區特定的方法才能實現轉換。

let stringValue = "hello world"; 
console.log(stringValue.toUpperCase());//"HELLO WORLD"
console.log(stringValue.toLocaleUpperCase());//"HELLO WORLD"
console.log(stringValue.toLocaleLowerCase());//"hello world"
console.log(stringValue.toLowerCase());// "hello world"

11.字符串模式匹配方法 match(),search(),replace(),split()

match()

String 類型專門為字符串中實現模式匹配設計瞭幾個方法。第一個就是match()方法,這個方法本質上跟RegExp對象的exec()方法相同。match()方法接收一個參數,可以是一個正則表達式字符串,也可以是一個RegExp對象

let text = "cat, bat, sat, fat";
let pattern = /.at/;

//等價於pattern.exec(text)
let matches = text.match(pattern); 
console.log(matches.index);//0
console.log(matches[0]);// "cat"
console.log(pattern.lastIndex);// 0

search()

另一個查找模式的字符串方法是search().這個方法唯一的參數與match()方法一樣:正則表達式或RegExp對象。這個方法返回模式第一個匹配的位置索引,如果沒有找到返回-1.search()始終從字符串開頭向後向後匹配模式。

let text = "cat, bat, sat, fat";
let pos = text.search(/at/);
console.log(pos);//1

replace()

為簡化字符串替換操作,ECMAScript提供瞭replace()方法。
這個方法接收兩個參數,第一個參數可以是一個RegExp對象或一個字符串(這個字符串不會轉化為正則表達式),第二個參可以是一個字符串或函數。
如果第一個參數是字符串,那麼隻會替換第一個字符串,要想替換所有子字符串,第一個參數必須為正則表達式並且帶全局標記。

let text = "cat, bat, sat, fat";
let result = text.replace("at","ond");
console.log(result);// "cond, bat, sat, fat"

result = text.replace(/at/g,"ond);
console.log(result);//"cond, bond, sond, fond"

第二個參數是字符串的情況下,有幾個特殊的字符序列,可以用來插入正則表達操作的值。 ECMAScript262 規定瞭如下的值。

字符序列 替換文本
$$ $
$& 匹配整個模式的子字符串。與RegExp.lastMatch相同
$' 匹配的子字符串之前的字符串。與RegExp.rightContext 相同
$` 匹配的子字符串之後的字符串。與RegExp.leftContext 相同
$n 匹配第n個捕獲組的字符串,其中n 是 0~9.比如,1 是匹配的第一個捕獲組的字符串,1是匹配的第一個捕獲組的字符串,2 是匹配的第二個捕獲組的字符串,以此類推。如果沒有捕獲組,則值為空字符串
$nn 匹配第nn個捕獲組字符串,其中nn 是01~99.比如,01 是匹配第一個捕獲組的字符串,01是匹配第一個捕獲組的字符串,02 是匹配第二個捕獲組的字符串,以此類推。如果沒有捕獲組,則值為空字符串

使用這些特殊的序列,可以在替換文中使用之前匹配的內容

let  text = "cat, bat, sat, fat";
result = text.replace(/(.at)/g,"word ($1)");
console.log(result); // word(cat), word(bat), word(sat), word(fat)

replace() 第二個參數可以是一個函數。在 在隻有一個匹配項時,這個函數會收到3個參數:與整個模式匹配的字符串,匹配項在字符串中的開始位置,以及整個字符串。在有多個捕獲組的情況下,每個匹配捕獲組的字符串也會作為參數傳遞這個函數,但最後兩個參數還是與整個模式匹配的開始位置和原始字符串。這個函數應該返回一個字符串,表示應該把撇皮項替換成什麼。使用函數作為第二個參數可以更細致的控制替換過程。

function  htmlEscape(text) {
    return text.replace(/[<>"&]/g,function(match,pos,originalText){
        switch(match) {
            case "<":
            return "&lt;";
            case  ">":
            return "&gt;";
            case "&":
            return "&amp;";
            case "\"":
            return "&quot;";
        }
    });
}

console.log(htmlEscape("<p class=\"greeting\">Hello world!<p>"));//&lt;p class=&quot;greeting&quot;&gt;Hello world!&lt;p&gt;

split()

最後一個與模式匹配相關的字符串方法是split().這個方法會根據傳入的分隔符將字符串拆分成數組。作為分隔符的參數可以是字符串,也可以是RegExp對象。(字符串分隔符不會被這個方法當成增則表達式。)還可以傳入第二個參數,即數組大小,確保返回的數組不會超過指定大小。

let colorText = "red,blue,green,yellow";
let color1 = colorText.split(",");// ["red","blue","green","yellow"]
let color2 = colorText.split(",",2);//["red","blue"];
let colors = colorText.split(/[^,]/);// ["",",",",",",",""]

12.localeCompare()

localCompare()方法比較兩個字符串,返回如下3個值中的一個:

  • 如果按照字母表順序,字符串應該排在字符串參數牽頭,則返回負值。(通常是-1,具體還要看實際值相關的實現。)
  • 如果字符串與字符串參數相等,則返回0
  • 如果按照字母表順序,字符串應該排在字符串參數後頭,則返回正值。(通常是1,具體還要看與實際值相關的實現)
let stringValue = "yellow";
console.log(stringValue.localeCompare("brick");//1
console.log(stringValue.localeCompare("yellow");// 0
console.log(stringValue.localeCompare("zoo");//-1

因為返回的具體值可能因為具體實現而異,所以最好像下面方式一樣使用localeCompare()

function detemineOrder(value){
    let result = stringValue.localeCompare(value);
    if(result < 0 ){
        console.log(`The string 'yellow' comes before the string '${value}'.`);
    }else if( result > 0) {
        console.log(`The string 'yellow' comes after the string '${value}'.`);
    }else {
      console.log(`The string 'yellow' comes equal the string '${value}'.`);
    }
}
detemineOrder("brick");
detemineOrder("yellow);
detemineOrder("zoo);

到此這篇關於JavaScript 引用類型之原始值包裝類型String的文章就介紹到這瞭,更多相關JS 裝類型String內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: