JavaScript字符串全部API全解密

關於

本文近 6k 字,讀完需 10 分鐘。javascript

字符串做爲基本的信息交流的橋樑,幾乎被全部的編程語言所實現(然而c、c++沒有提供)。多數開發者幾乎天天都在和字符串打交道,語言內置的String模塊,極大地提高了開發者的效率。JavaScript經過自動裝箱字符串字面量爲String對象,天然地繼承了String.prototype的全部方法,更加簡化了字符串的使用。html

截止ES6,字符串共包含31個標準的API方法,其中有些方法出鏡率較高,須要摸透原理;有些方法之間類似度較高,須要仔細分辨;甚至有些方法執行效率較低,應當儘可能少的使用。下面將從String構造器方法提及,逐步幫助你掌握字符串。前端

String構造器方法

fromCharCode

fromCharCode() 方法返回使用指定的Unicode序列建立的字符串,也就是說傳入Unicode序列,返回基於此建立的字符串。java

語法:fromCharCode(num1, num2,…),傳入的參數均爲數字。python

以下這是一個簡單的例子,將返回 ABC、abc、*、+、- 和 /:c++

String.fromCharCode(65, 66, 67); // "ABC"
String.fromCharCode(97, 98, 99); // "abc"
String.fromCharCode(42); // "*"
String.fromCharCode(43); // "+"
String.fromCharCode(45); // "-"
String.fromCharCode(47); // "/"複製代碼

看起來fromCharCode像是知足了需求,但實際上因爲js語言設計時的先天不足(只能處理UCS-2編碼,即全部字符都是2個字節,沒法處理4字節字符),經過該方法並不能返回一個4字節的字符,爲了彌補這個缺陷,ES6新增了fromCodePoint方法,請往下看。git

fromCodePoint(ES6)

fromCodePoint() 方法基於ECMAScript 2015(ES6)規範,做用和語法同fromCharCode方法,該方法主要擴展了對4字節字符的支持。es6

// "𝌆" 是一個4字節字符,咱們先看下它的數字形式
"𝌆".codePointAt(); // 119558
//調用fromCharCode解析之,返回亂碼
String.fromCharCode(119558); // "팆"
//調用fromCodePoint解析之,正常解析
String.fromCodePoint(119558); // "𝌆"複製代碼

除了擴展對4字節的支持外,fromCodePoint還規範了錯誤處理,只要是無效的Unicode編碼,就會拋出錯誤RangeError: Invalid code point...,這就意味着,只要不是符合Unicode字符範圍的正整數(Unicode最多可容納1114112個碼位),均會拋出錯誤。github

String.fromCodePoint('abc'); // RangeError: Invalid code point NaN
String.fromCodePoint(Infinity); // RangeError: Invalid code point Infinity
String.fromCodePoint(-1.23); // RangeError: Invalid code point -1.23複製代碼

注:進一步瞭解Unicode編碼,推薦這篇文章:淺談文字編碼和Unicode(下)。如需在老的瀏覽器中使用該方法,請參考Polyfill正則表達式

raw(ES6)

raw() 方法基於ECMAScript 2015(ES6)規範,它是一個模板字符串的標籤函數,做用相似於Python的r和C#的@字符串前綴,都是用來獲取一個模板字符串的原始字面量。

語法: String.raw(callSite, ...substitutions),callSite即模板字符串的『調用點對象』,...substitutions表示任意個內插表達式對應的值,這裏理解起來至關拗口,下面我將通俗的講解它。

以下是python的字符串前綴r:

# 防止特殊字符串被轉義
print r'a\nb\tc' # 打印出來依然是 "a\nb\tc"
# python中經常使用於正則表達式
regExp = r'(?<=123)[a-z]+'複製代碼

以下是String.raw做爲前綴的用法:

// 防止特殊字符串被轉義
String.raw`a\nb\tc`; // 輸出爲 "a\nb\tc"
// 支持內插表達式
let name = "louis";
String.raw`Hello \n ${name}`;  // "Hello \n louis"
// 內插表達式還能夠運算
String.raw`1+2=${1+2},2*3=${2*3}`; // "1+2=3,2*3=6"複製代碼

String.raw做爲函數來調用的場景不太多,以下是用法:

// 對象的raw屬性值爲字符串時,從第二個參數起,它們分別被插入到下標爲0,1,2,...n的元素後面
String.raw({raw: 'abcd'}, 1, 2, 3); // "a1b2c3d"
// 對象的raw屬性值爲數組時,從第二個參數起,它們分別被插入到數組下標爲0,1,2,...n的元素後面
String.raw({raw: ['a', 'b', 'c', 'd']}, 1, 2, 3); // "a1b2c3d"複製代碼

那麼怎麼解釋String.raw函數按照下標挨個去插入的特性呢?MDN上有段描述以下:

In most cases, String.raw() is used with template strings. The first syntax mentioned above is only rarely used, because the JavaScript engine will call this with proper arguments for you, just like with other tag functions.

這意味着,String.raw做爲函數調用時,基本與ES6的tag標籤模板同樣。以下:

// 以下是tag函數的實現
function tag(){
  const array = arguments[0];
  return array.reduce((p, v, i) => p + (arguments[i] || '') + v);
}
// 回顧一個simple的tag標籤模板
tag`Hello ${ 2 + 3 } world ${ 2 * 3 }`; // "Hello 5 world 6"
// 其實就想當於以下調用
tag(['Hello ', ' world ', ''], 5, 6); // "Hello 5 world 6"複製代碼

所以String.raw做爲函數調用時,不論對象的raw屬性值是字符串仍是數組,插槽都是天生的,下標爲0,1,2,...n的元素後面都是插槽(不包括最後一個元素)。實際上,它至關因而這樣的tag函數:

function tag(){
  const array = arguments[0].raw;
  if(array === undefined || array === null){ // 這裏可簡寫成 array == undefined
    throw new TypeError('Cannot convert undefined or null to object');
  }
  return array.reduce((p, v, i) => p + (arguments[i] || '') + v);
}複製代碼

實際上,String.raw做爲函數調用時,若第一個參數不是一個符合標準格式的對象,執行將拋出TypeError錯誤。

String.raw({123: 'abcd'}, 1, 2, 3); // TypeError: Cannot convert undefined or null to object複製代碼

目前只有Chrome v41+和Firefox v34+版本瀏覽器實現了該方法。

String.prototype

和其餘全部對象同樣,字符串實例的全部方法均來自String.prototype。如下是它的屬性特性:

writable false
enumerable false
configurable false

可見,字符串屬性不可編輯,任何試圖改變它屬性的行爲都將拋出錯誤。

屬性

String.prototype共有兩個屬性,以下:

  • String.prototype.constructor 指向構造器(String())
  • String.prototype.length 表示字符串長度

方法

字符串原型方法分爲兩種,一種是html無關的方法,一種是html有關的方法。咱們先看第一種。可是不管字符串方法如何厲害,都不至於強大到能夠改變原字符串。

HTML無關的方法

經常使用的方法有,charAt、charCodeAt、concat、indexOf、lastIndexOf、localeCompare、match、replace、search、slice、split、substr、substring、toLocaleLowerCase、toLocaleUpperCase、toLowerCase、toString、toUpperCase、trim、valueof 等ES5支持的,以及 codePointAt、contains、endsWith、normalize、repeat、startsWith 等ES6支持的,還包括 quote、toSource、trimLeft、trimRight 等非標準的。

接下來咱們將對各個方法分別舉例闡述其用法。若沒有特別說明,默認該方法兼容全部目前主流瀏覽器。

charAt

charAt() 方法返回字符串中指定位置的字符。

語法:str.charAt(index)

index 爲字符串索引(取值從0至length-1),若是超出該範圍,則返回空串。

console.log("Hello, World".charAt(8)); // o, 返回下標爲8的字符串o複製代碼
charCodeAt

charCodeAt() 返回指定索引處字符的 Unicode 數值。

語法:str.charCodeAt(index)

index 爲一個從0至length-1的整數。若是不是一個數值,則默認爲 0,若是小於0或者大於字符串長度,則返回 NaN。

Unicode 編碼單元(code points)的範圍從 0 到 1,114,111。開頭的 128 個 Unicode 編碼單元和 ASCII 字符編碼同樣.

charCodeAt() 老是返回一個小於 65,536 的值。由於高位編碼單元須要由一對字符來表示,爲了查看其編碼的完成字符,須要查看 charCodeAt(i) 以及 charCodeAt(i+1) 的值。如需更多瞭解請參考 fixedCharCodeAt

console.log("Hello, World".charCodeAt(8)); // 111
console.log("前端工程師".charCodeAt(2)); // 24037, 可見也能夠查看中文Unicode編碼複製代碼
concat

concat() 方法將一個或多個字符串拼接在一塊兒,組成新的字符串並返回。

語法:str.concat(string2, string3, …)

console.log("早".concat("上","好")); // 早上好複製代碼

可是 concat 的性能表現不佳,強烈推薦使用賦值操做符(+或+=)代替 concat。"+" 操做符大概快了 concat 幾十倍。(數據參考 性能測試)。

indexOf
lastIndexOf

indexOf() 方法用於查找子字符串在字符串中首次出現的位置,沒有則返回 -1。該方法嚴格區分大小寫,而且從左往右查找。而 lastIndexOf 則從右往左查找,其它與前者一致。

語法:str.indexOf(searchValue [, fromIndex=0])str.lastIndexOf(searchValue [, fromIndex=0])

searchValue 表示被查找的字符串,fromIndex 表示開始查找的位置,默認爲0,若是小於0,則查找整個字符串,若超過字符串長度,則該方法返回-1,除非被查找的是空字符串,此時返回字符串長度。

console.log("".indexOf("",100)); // 0
console.log("IT改變世界".indexOf("世界")); // 4
console.log("IT改變世界".lastIndexOf("世界")); // 4複製代碼
localeCompare

localeCompare() 方法用來比較字符串,若是指定字符串在原字符串的前面則返回負數,不然返回正數或0,其中0 表示兩個字符串相同。該方法實現依賴具體的本地實現,不一樣的語言下可能有不一樣的返回。

語法:str.localeCompare(str2 [, locales [, options]])

var str = "apple";
var str2 = "orange";
console.log(str.localeCompare(str2)); // -1
console.log(str.localeCompare("123")); // 1複製代碼

目前 Safari 瀏覽器暫不支持該方法,但Chrome v24+、Firefox v29+,IE11+ 和 Opera v15+ 都已實現了它。

match

match() 方法用於測試字符串是否支持指定正則表達式的規則,即便傳入的是非正則表達式對象,它也會隱式地使用new RegExp(obj)將其轉換爲正則表達式對象。

語法:str.match(regexp)

該方法返回包含匹配結果的數組,若是沒有匹配項,則返回 null。

描述

  • 若正則表達式沒有 g 標誌,則返回同 RegExp.exec(str) 相同的結果。並且返回的數組擁有一個額外的 input 屬性,該屬性包含原始字符串,另外該數組還擁有一個 index 屬性,該屬性表示匹配字符串在原字符串中索引(從0開始)。
  • 若正則表達式包含 g 標誌,則該方法返回一個包含全部匹配結果的數組,沒有匹配到則返回 null。

相關 RegExp 方法

  • 若需測試字符串是否匹配正則,請參考 RegExp.test(str)。
  • 若只需第一個匹配結果,請參考 RegExp.exec(str)。
var str = "World Internet Conference";
console.log(str.match(/[a-d]/i)); // ["d", index: 4, input: "World Internet Conference"]
console.log(str.match(/[a-d]/gi)); // ["d", "C", "c"]
// RegExp 方法以下
console.log(/[a-d]/gi.test(str)); // true
console.log(/[a-d]/gi.exec(str)); // ["d", index: 4, input: "World Internet Conference"]複製代碼

由上可知,RegExp.test(str) 方法只要匹配到了一個字符也返回true。而RegExp.exec(str) 方法不管正則中有沒有包含 g 標誌,RegExp.exec將直接返回第一個匹配結果,且該結果同 str.match(regexp) 方法不包含 g 標誌時的返回一致。

replace

該方法在以前已經講過,詳細請參考 String.prototype.replace高階技能

search

search() 方法用於測試字符串對象是否包含某個正則匹配,至關於正則表達式的 test 方法,且該方法比 match() 方法更快。若是匹配成功,search() 返回正則表達式在字符串中首次匹配項的索引,不然返回-1。

注意:search方法與indexOf方法做用基本一致,都是查詢到了就返回子串第一次出現的下標,不然返回-1,惟一的區別就在於search默認會將子串轉化爲正則表達式形式,而indexOf不作此處理,也不能處理正則。

語法:str.search(regexp)

var str = "abcdefg";
console.log(str.search(/[d-g]/)); // 3, 匹配到子串"defg",而d在原字符串中的索引爲3複製代碼

search() 方法不支持全局匹配(正則中包含g參數),以下:

console.log(str.search(/[d-g]/g)); // 3, 與無g參數時,返回相同複製代碼
slice

slice() 方法提取字符串的一部分,並返回新的字符串。該方法有些相似 Array.prototype.slice 方法。

語法:str.slice(start, end)

首先 end 參數可選,start可取正值,也可取負值。

取正值時表示從索引爲start的位置截取到end的位置(不包括end所在位置的字符,若是end省略則截取到字符串末尾)。

取負值時表示從索引爲 length+start 位置截取到end所在位置的字符。

var str = "It is our choices that show what we truly are, far more than our abilities.";
console.log(str.slice(0,-30)); // It is our choices that show what we truly are
console.log(str.slice(-30)); // , far more than our abilities.複製代碼
split

split() 方法把原字符串分割成子字符串組成數組,並返回該數組。

語法:str.split(separator, limit)

兩個參數均是可選的,其中 separator 表示分隔符,它能夠是字符串也能夠是正則表達式。若是忽略 separator,則返回的數組包含一個由原字符串組成的元素。若是 separator 是一個空串,則 str 將會被分割成一個由原字符串中字符組成的數組。limit 表示從返回的數組中截取前 limit 個元素,從而限定返回的數組長度。

var str = "today is a sunny day";
console.log(str.split()); // ["today is a sunny day"]
console.log(str.split("")); // ["t", "o", "d", "a", "y", " ", "i", "s", " ", "a", " ", "s", "u", "n", "n", "y", " ", "d", "a", "y"]
console.log(str.split(" ")); // ["today", "is", "a", "sunny", "day"]複製代碼

使用limit限定返回的數組大小,以下:

console.log(str.split(" ")); // ["today"]複製代碼

使用正則分隔符(RegExp separator), 以下:

console.log(str.split(/\s*is\s*/)); // ["today", "a sunny day"]複製代碼

若正則分隔符裏包含捕獲括號,則括號匹配的結果將會包含在返回的數組中。

console.log(str.split(/(\s*is\s*)/)); // ["today", " is ", "a sunny day"]複製代碼
substr

substr() 方法返回字符串指定位置開始的指定數量的字符。

語法:str.substr(start[, length])

start 表示開始截取字符的位置,可取正值或負值。取正值時表示start位置的索引,取負值時表示 length+start位置的索引。

length 表示截取的字符長度。

var str = "Yesterday is history. Tomorrow is mystery. But today is a gift.";
console.log(str.substr(47)); // today is a gift.
console.log(str.substr(-16)); // today is a gift.複製代碼

目前 Microsoft's JScript 不支持 start 參數取負的索引,如需在 IE 下支持,請參考 Polyfill

substring

substring() 方法返回字符串兩個索引之間的子串。

語法:str.substring(indexA[, indexB])

indexA、indexB 表示字符串索引,其中 indexB 可選,若是省略,則表示返回從 indexA 到字符串末尾的子串。

描述

substring 要截取的是從 indexA 到 indexB(不包含)之間的字符,符合如下規律:

  • 若 indexA == indexB,則返回一個空字符串;
  • 若 省略 indexB,則提取字符一直到字符串末尾;
  • 若 任一參數小於 0 或 NaN,則被看成 0;
  • 若 任一參數大於 length,則被看成 length。

而 若是 indexA > indexB,則 substring 的執行效果就像是兩個參數調換通常。好比:str.substring(0, 1) == str.substring(1, 0)

var str = "Get outside every day. Miracles are waiting everywhere.";
console.log(str.substring(1,1)); // ""
console.log(str.substring(0)); // Get outside every day. Miracles are waiting everywhere.
console.log(str.substring(-1)); // Get outside every day. Miracles are waiting everywhere.
console.log(str.substring(0,100)); // Get outside every day. Miracles are waiting everywhere.
console.log(str.substring(22,NaN)); // Get outside every day.複製代碼
toLocaleLowerCase
toLocaleUpperCase

toLocaleLowerCase() 方法返回調用該方法的字符串被轉換成小寫的值,轉換規則根據本地化的大小寫映射。而toLocaleUpperCase() 方法則是轉換成大寫的值。

語法:str.toLocaleLowerCase(), str.toLocaleUpperCase()

console.log('ABCDEFG'.toLocaleLowerCase()); // abcdefg
console.log('abcdefg'.toLocaleUpperCase()); // ABCDEFG複製代碼
toLowerCase
toUpperCase

這兩個方法分別表示將字符串轉換爲相應的小寫,大寫形式,並返回。以下:

console.log('ABCDEFG'.toLowerCase()); // abcdefg
console.log('abcdefg'.toUpperCase()); // ABCDEFG複製代碼
toString
valueOf

這兩個方法都是返回字符串自己。

語法:str.toString(), str.valueOf()

var str = "abc";
console.log(str.toString()); // abc
console.log(str.toString()==str.valueOf()); // true複製代碼

對於對象而言,toString和valueOf也是很是的類似,它們之間有着細微的差異,請嘗試運行如下一段代碼:

var x = {
    toString: function () { return "test"; },
    valueOf: function () { return 123; }
};

console.log(x); // test
console.log("x=" + x); // "x=123"
console.log(x + "=x"); // "123=x"
console.log(x + "1"); // 1231
console.log(x + 1); // 124
console.log(["x=", x].join("")); // "x=test"複製代碼

當 "+" 操做符一邊爲數字時,對象x趨向於轉換爲數字,表達式會優先調用 valueOf 方法,若是調用數組的 join 方法,對象x趨向於轉換爲字符串,表達式會優先調用 toString 方法。

trim

trim() 方法清除字符串首尾的空白並返回。

語法:str.trim()

console.log(" a b c ".trim()); // "a b c"複製代碼

trim() 方法是 ECMAScript 5.1 標準加入的,它並不支持IE9如下的低版本IE瀏覽器,如需支持,請參考如下兼容寫法:

if(!String.prototype.trim) {
  String.prototype.trim = function () {
    return this.replace(/^\s+|\s+$/g,'');
  };
}複製代碼
codePointAt(ES6)

codePointAt() 方法基於ECMAScript 2015(ES6)規範,返回使用UTF-16編碼的給定位置的值的非負整數。

語法:str.codePointAt(position)

console.log("a".codePointAt(0)); // 97
console.log("\u4f60\u597d".codePointAt(0)); // 20320複製代碼

如需在老的瀏覽器中使用該方法,請參考 Polyfill

includes(ES6)

includes() 方法基於ECMAScript 2015(ES6)規範,它用來判斷一個字符串是否屬於另外一個字符。若是是,則返回true,不然返回false。

語法:str.includes(subString [, position])

subString 表示要搜索的字符串,position 表示從當前字符串的哪一個位置開始搜索字符串,默認值爲0。

var str = "Practice makes perfect.";
console.log(str.includes("perfect")); // true
console.log(str.includes("perfect",100)); // false複製代碼

實際上,Firefox 18~39中該方法的名稱爲contains,因爲bug 1102219的存在,它被重命名爲includes() 。目前只有Chrome v41+和Firefox v40+版本瀏覽器實現了它,如需在其它版本瀏覽器中使用該方法,請參考 Polyfill

endsWith(ES6)

endsWith() 方法基於ECMAScript 2015(ES6)規範,它基本與 contains() 功能相同,不一樣的是,它用來判斷一個字符串是不是原字符串的結尾。如果則返回true,不然返回false。

語法:str.endsWith(substring [, position])

與contains 方法不一樣,position 參數的默認值爲字符串長度。

var str = "Learn and live.";
console.log(str.endsWith("live.")); // true
console.log(str.endsWith("Learn",5)); // true複製代碼

一樣目前只有 Firefox v17+版本實現了該方法。其它瀏覽器請參考 Polyfill

normalize(ES6)

normalize() 方法基於ECMAScript 2015(ES6)規範,它會按照指定的 Unicode 正規形式將原字符串正規化。

語法:str.normalize([form])

form 參數可省略,目前有四種 Unicode 正規形式,即 "NFC"、"NFD"、"NFKC" 以及 "NFKD",form的默認值爲 "NFC"。若是form 傳入了非法的參數值,則會拋出 RangeError 錯誤。

var str = "\u4f60\u597d";
console.log(str.normalize()); // 你好
console.log(str.normalize("NFC")); // 你好
console.log(str.normalize("NFD")); // 你好
console.log(str.normalize("NFKC")); // 你好
console.log(str.normalize("NFKD")); // 你好複製代碼

目前只有Chrome v34+和Firefox v31+實現了它。

repeat(ES6)

repeat() 方法基於ECMAScript 2015(ES6)規範,它返回重複原字符串屢次的新字符串。

語法:str.repeat(count)

count 參數只能取大於等於0 的數字。若該數字不爲整數,將自動轉換爲整數形式,若爲負數或者其餘值將報錯。

var str = "A still tongue makes a wise head.";
console.log(str.repeat(0)); // ""
console.log(str.repeat(1)); // A still tongue makes a wise head.
console.log(str.repeat(1.5)); // A still tongue makes a wise head.
console.log(str.repeat(-1)); // RangeError:Invalid count value複製代碼

目前只有 Chrome v41+、Firefox v24+和Safari v9+版本瀏覽器實現了該方法。其餘瀏覽器請參考 Polyfill

startsWith(ES6)

startsWith() 方法基於ECMAScript 2015(ES6)規範,它用來判斷當前字符串是不是以給定字符串開始的,如果則返回true,不然返回false。

語法:str.startsWith(subString [, position])

var str = "Where there is a will, there is a way.";
console.log(str.startsWith("Where")); // true
console.log(str.startsWith("there",6)); // true複製代碼

目前如下版本瀏覽器實現了該方法,其餘瀏覽器請參考 Polyfill

Chrome Firefox Edge Opera Safari
41+ 17+ ✔️ 28+ 9+

其它非標準的方法暫時不做介紹,如需瞭解請參考 String.prototype 中標註爲感嘆號的方法。

HTML有關的方法

經常使用的方法有 anchor,link 其它方法如 big、blink、bold、fixed、fontcolor、fontsize、italics、small、strike、sub、sup均已廢除。

接下來咱們將介紹 anchor 和 link 兩個方法,其餘廢除方法不做介紹。

anchor

anchor() 方法建立一個錨標籤。

語法:str.anchor(name)

name 指定被建立的a標籤的name屬性,使用該方法建立的錨點,將會成爲 document.anchors 數組的元素。

var str = "this is a anchor tag";
document.body.innerHTML = document.body.innerHTML + str.anchor("anchor1"); // body末尾將會追加這些內容 <a name="anchor1">this is a anchor tag</a>複製代碼

link() 方法一樣建立一個a標籤。

語法:str.link(url)

url 指定被建立的a標籤的href屬性,若是url中包含特殊字符,將自動進行編碼。例如 " 會被轉義爲 &\quot。 使用該方法建立的a標籤,將會成爲 document.links 數組中的元素。

var str = "百度";
document.write(str.link("https://www.baidu.com")); // <a href="https://www.baidu.com">百度</a>複製代碼

小結

部分字符串方法之間存在很大的類似性,要注意區分他們的功能和使用場景。如:

  • substr 和 substring,都是兩個參數,做用基本相同,二者第一個參數含義相同,但用法不一樣,前者可爲負數,後者值爲負數或者非整數時將隱式轉換爲0。前者第二個參數表示截取字符串的長度,後者第二個參數表示截取字符串的下標;同時substring第一個參數大於第二個參數時,執行結果同位置調換後的結果。
  • search方法與indexOf方法做用基本一致,都是查詢到了就返回子串第一次出現的下標,不然返回-1,惟一的區別就在於search默認會將子串轉化爲正則表達式形式,而indexOf不作此處理,也不能處理正則。

另外,還記得嗎?concat方法因爲效率問題,不推薦使用。

一般,字符串中,經常使用的方法就charAt、indexOf、lastIndexOf、match、replace、search、slice、split、substr、substring、toLowerCase、toUpperCase、trim、valueof 等這些。熟悉它們的語法規則就能熟練地駕馭字符串。


本文就討論這麼多內容,你們有什麼問題或好的想法歡迎在下方參與留言和評論。

本文做者:louis

本文連接:louiszhai.github.io/2016/01/12/…

參考文章

相關文章
相關標籤/搜索