在 JavaScript 中,文本數據被以字符串形式存儲,單個字符沒有單獨的類型。
字符串的內部格式始終是 UTF-16,它不依賴于頁面編碼。
讓我們回憶壹下引號的種類。
字符串可以包含在單引號、雙引號或反引號中:
let single = 'single-quoted'; let double = "double-quoted"; let backticks = `backticks`;
單引號和雙引號基本相同。但是,反引號允許我們通過 ${…}
將任何表達式嵌入到字符串中:
function sum(a, b) { return a + b; } alert(`1 + 2 = ${sum(1, 2)}.`); // 1 + 2 = 3.
使用反引號的另壹個優點是它們允許字符串跨行:
let guestList = `Guests: * John * Pete * Mary `; alert(guestList); // 客人清單,多行
看起來很自然,不是嗎?但是單引號和雙引號可不能這樣做。
如果我們使用單引號或雙引號來實現字符串跨行的話,則會出現錯誤:
let guestList = "Guests: // Error: Unexpected token ILLEGAL * John";
單引號和雙引號來自語言創建的古老時代,當時沒有考慮到多行字符串的需要。反引號出現較晚,因此更通用。
反引號還允許我們在第壹個反引號之前指定壹個“模版函數”。語法是:func`string`
。函數 func
被自動調用,接收字符串和嵌入式表達式,並處理它們。妳可以在 docs 中閱讀更多關于它們的信息。這叫做 “tagged templates”。此功能可以更輕松地將字符串包裝到自定義模版或其他函數中,但這很少使用。
我們仍然可以通過使用“換行符(newline character)”,以支持使用單引號和雙引號來創建跨行字符串。換行符寫作 n
,用來表示換行:
let guestList = "Guests:n * Johnn * Peten * Mary"; alert(guestList); // 壹個多行的客人列表
例如,這兩行描述的是壹樣的,只是書寫方式不同:
let str1 = "HellonWorld"; // 使用“換行符”創建的兩行字符串 // 使用反引號和普通的換行創建的兩行字符串 let str2 = `Hello World`; alert(str1 == str2); // true
還有其他不常見的“特殊”字符。
這是完整列表:
字符 | 描述 |
---|---|
n | 換行 |
r | 在 Windows 文本文件中,兩個字符 rn 的組合代表壹個換行。而在非 Windows 操作系統上,它就是 n 。這是曆史原因造成的,大多數的 Windows 軟件也理解 n 。 |
' , " | 引號 |
\ | 反斜線 |
t | 制表符 |
b , f , v | 退格,換頁,垂直標簽 —— 爲了兼容性,現在已經不使用了。 |
xXX | 具有給定十六進制 Unicode XX 的 Unicode 字符,例如:'x7A' 和 'z' 相同。 |
uXXXX | 以 UTF-16 編碼的十六進制代碼 XXXX 的 Unicode 字符,例如 u00A9 —— 是版權符號 © 的 Unicode。它必須正好是 4 個十六進制數字。 |
u{X…XXXXXX} (1 到 6 個十六進制字符) | 具有給定 UTF-32 編碼的 Unicode 符號。壹些罕見的字符用兩個 Unicode 符號編碼,占用 4 個字節。這樣我們就可以插入長代碼了。 |
Unicode 示例:
alert( "u00A9" ); // © alert( "u{20331}" ); // 佫,罕見的中國象形文字(長 Unicode) alert( "u{1F60D}" ); // ?,笑臉符號(另壹個長 Unicode)
所有的特殊字符都以反斜杠字符 開始。它也被稱爲“轉義字符”。
如果我們想要在字符串中插入壹個引號,我們也會使用它。
例如:
alert( 'I'm the Walrus!' ); // I'm the Walrus!
正如妳所看到的,我們必須在內部引號前加上反斜杠 '
,否則它將表示字符串結束。
當然,只有與外部閉合引號相同的引號才需要轉義。因此,作爲壹個更優雅的解決方案,我們可以改用雙引號或者反引號:
alert( `I'm the Walrus!` ); // I'm the Walrus!
注意反斜杠 在 JavaScript 中用于正確讀取字符串,然後消失。內存中的字符串沒有
。妳從上述示例中的
alert
可以清楚地看到這壹點。
但是如果我們需要在字符串中顯示壹個實際的反斜杠 應該怎麽做?
我們可以這樣做,只需要將其書寫兩次 \
:
alert( `The backslash: \` ); // The backslash:
length
屬性表示字符串長度:
alert( `Myn`.length ); // 3
注意 n
是壹個單獨的“特殊”字符,所以長度確實是 3
。
length
是壹個屬性
掌握其他編程語言的人,有時會錯誤地調用 str.length()
而不是 str.length
。這是行不通的。
請注意 str.length
是壹個數字屬性,而不是函數。後面不需要添加括號。
要獲取在 pos
位置的壹個字符,可以使用方括號 [pos]
或者調用 str.charAt(pos) 方法。第壹個字符從零位置開始:
let str = `Hello`; // 第壹個字符 alert( str[0] ); // H alert( str.charAt(0) ); // H // 最後壹個字符 alert( str[str.length - 1] ); // o
方括號是獲取字符的壹種現代化方法,而 charAt
是曆史原因才存在的。
它們之間的唯壹區別是,如果沒有找到字符,[]
返回 undefined
,而 charAt
返回壹個空字符串:
let str = `Hello`; alert( str[1000] ); // undefined alert( str.charAt(1000) ); // ''(空字符串)
我們也可以使用 for..of
遍曆字符:
for (let char of "Hello") { alert(char); // H,e,l,l,o(char 變爲 "H",然後是 "e",然後是 "l" 等) }
在 JavaScript 中,字符串不可更改。改變字符是不可能的。
我們證明壹下爲什麽不可能:
let str = 'Hi'; str[0] = 'h'; // error alert( str[0] ); // 無法運行
通常的解決方法是創建壹個新的字符串,並將其分配給 str
而不是以前的字符串。
例如:
let str = 'Hi'; str = 'h' + str[1]; // 替換字符串 alert( str ); // hi
在接下來的章節,我們將看到更多相關示例。
toLowerCase() 和 toUpperCase() 方法可以改變大小寫:
alert( 'Interface'.toUpperCase() ); // INTERFACE alert( 'Interface'.toLowerCase() ); // interface
或者我們想要使壹個字符變成小寫:
alert( 'Interface'[0].toLowerCase() ); // 'i'
在字符串中查找子字符串有很多種方法。
第壹個方法是 str.indexOf(substr, pos)。
它從給定位置 pos
開始,在 str
中查找 substr
,如果沒有找到,則返回 -1
,否則返回匹配成功的位置。
例如:
let str = 'Widget with id'; alert( str.indexOf('Widget') ); // 0,因爲 'Widget' 壹開始就被找到 alert( str.indexOf('widget') ); // -1,沒有找到,檢索是大小寫敏感的 alert( str.indexOf("id") ); // 1,"id" 在位置 1 處(……idget 和 id)
可選的第二個參數允許我們從壹個給定的位置開始檢索。
例如,"id"
第壹次出現的位置是 1
。查詢下壹個存在位置時,我們從 2
開始檢索:
let str = 'Widget with id'; alert( str.indexOf('id', 2) ) // 12
如果我們對所有存在位置都感興趣,可以在壹個循環中使用 indexOf
。每壹次新的調用都發生在上壹匹配位置之後:
let str = 'As sly as a fox, as strong as an ox'; let target = 'as'; // 這是我們要查找的目標 let pos = 0; while (true) { let foundPos = str.indexOf(target, pos); if (foundPos == -1) break; alert( `Found at ${foundPos}` ); pos = foundPos + 1; // 繼續從下壹個位置查找 }
相同的算法可以簡寫:
let str = "As sly as a fox, as strong as an ox"; let target = "as"; let pos = -1; while ((pos = str.indexOf(target, pos + 1)) != -1) { alert( pos ); }
str.lastIndexOf(substr, pos)
還有壹個類似的方法 str.lastIndexOf(substr, position),它從字符串的末尾開始搜索到開頭。
它會以相反的順序列出這些事件。
在 if
測試中 indexOf
有壹點不方便。我們不能像這樣把它放在 if
中:
let str = "Widget with id"; if (str.indexOf("Widget")) { alert("We found it"); // 不工作! }
上述示例中的 alert
不會顯示,因爲 str.indexOf("Widget")
返回 0
(意思是它在起始位置就查找到了匹配項)。是的,但是 if
認爲 0
表示 false
。
因此我們應該檢查 -1
,像這樣:
let str = "Widget with id"; if (str.indexOf("Widget") != -1) { alert("We found it"); // 現在工作了! }
這裏使用的壹個老技巧是 bitwise NOT ~
運算符。它將數字轉換爲 32-bit 整數(如果存在小數部分,則刪除小數部分),然後對其二進制表示形式中的所有位均取反。
實際上,這意味著壹件很簡單的事兒:對于 32-bit 整數,~n
等于 -(n+1)
。
例如:
alert( ~2 ); // -3,和 -(2+1) 相同 alert( ~1 ); // -2,和 -(1+1) 相同 alert( ~0 ); // -1,和 -(0+1) 相同 alert( ~-1 ); // 0,和 -(-1+1) 相同
正如我們看到這樣,只有當 n == -1
時,~n
才爲零(適用于任何 32-bit 帶符號的整數 n
)。
因此,僅當 indexOf
的結果不是 -1
時,檢查 if ( ~str.indexOf("...") )
才爲真。換句話說,當有匹配時。
人們用它來簡寫 indexOf
檢查:
let str = "Widget"; if (~str.indexOf("Widget")) { alert( 'Found it!' ); // 正常運行 }
通常不建議以非顯而易見的方式使用語言特性,但這種特殊技巧在舊代碼中仍被廣泛使用,所以我們應該理解它。
只要記住:if (~str.indexOf(...))
讀作 “if found”。
確切地說,由于 ~
運算符將大數字截斷爲 32 位,因此存在給出 0
的其他數字,最小的數字是 ~4294967295=0
。這使得這種檢查只有在字符串沒有那麽長的情況下才是正確的。
現在我們只會在舊的代碼中看到這個技巧,因爲現代 JavaScript 提供了 .includes
方法(見下文)。
更現代的方法 str.includes(substr, pos) 根據 str
中是否包含 substr
來返回 true/false
。
如果我們需要檢測匹配,但不需要它的位置,那麽這是正確的選擇:
alert( "Widget with id".includes("Widget") ); // true alert( "Hello".includes("Bye") ); // false
str.includes
的第二個可選參數是開始搜索的起始位置:
alert( "Widget".includes("id") ); // true alert( "Widget".includes("id", 3) ); // false, 從位置 3 開始沒有 "id"
方法 str.startsWith 和 str.endsWith 的功能與其名稱所表示的意思相同:
alert( "Widget".startsWith("Wid") ); // true,"Widget" 以 "Wid" 開始 alert( "Widget".endsWith("get") ); // true,"Widget" 以 "get" 結束
JavaScript 中有三種獲取字符串的方法:substring
、substr
和 slice
。
str.slice(start [, end])
返回字符串從 start
到(但不包括)end
的部分。
例如:
let str = "stringify"; alert( str.slice(0, 5) ); // 'strin',從 0 到 5 的子字符串(不包括 5) alert( str.slice(0, 1) ); // 's',從 0 到 1,但不包括 1,所以只有在 0 處的字符
如果沒有第二個參數,slice
會壹直運行到字符串末尾:
let str = "stringify"; alert( str.slice(2) ); // 從第二個位置直到結束
start/end
也有可能是負值。它們的意思是起始位置從字符串結尾計算:
let str = "stringify"; // 從右邊的第四個位置開始,在右邊的第壹個位置結束 alert( str.slice(-4, -1) ); // 'gif'
str.substring(start [, end])
返回字符串從 start
到(但不包括)end
的部分。
這與 slice
幾乎相同,但它允許 start
大于 end
。
例如:
let str = "stringify"; // 這些對于 substring 是相同的 alert( str.substring(2, 6) ); // "ring" alert( str.substring(6, 2) ); // "ring" // ……但對 slice 是不同的: alert( str.slice(2, 6) ); // "ring"(壹樣) alert( str.slice(6, 2) ); // ""(空字符串)
不支持負參數(不像 slice),它們被視爲 0
。
str.substr(start [, length])
返回字符串從 start
開始的給定 length
的部分。
與以前的方法相比,這個允許我們指定 length
而不是結束位置:
let str = "stringify"; alert( str.substr(2, 4) ); // 'ring',從位置 2 開始,獲取 4 個字符
第壹個參數可能是負數,從結尾算起:
let str = "stringify"; alert( str.substr(-4, 2) ); // 'gi',從第 4 位獲取 2 個字符
我們回顧壹下這些方法,以免混淆:
方法 | 選擇方式…… | 負值參數 |
---|---|---|
slice(start, end) | 從 start 到 end (不含 end ) | 允許 |
substring(start, end) | 從 start 到 end (不含 end ) | 負值被視爲 0 |
substr(start, length) | 從 start 開始獲取長爲 length 的字符串 | 允許 start 爲負數 |
使用哪壹個?
它們都可用于獲取子字符串。正式壹點來講,substr
有壹個小缺點:它不是在 JavaScript 核心規範中描述的,而是在附錄 B 中。附錄 B 的內容主要是描述因曆史原因而遺留下來的僅浏覽器特性。因此,理論上非浏覽器環境可能無法支持 substr
,但實際上它在別的地方也都能用。
相較于其他兩個變體,slice
稍微靈活壹些,它允許以負值作爲參數並且寫法更簡短。因此僅僅記住這三種方法中的 slice
就足夠了。
正如我們從 值的比較 壹章中了解到的,字符串按字母順序逐字比較。
不過,也有壹些奇怪的地方。
小寫字母總是大于大寫字母:
alert( 'a' > 'Z' ); // true
帶變音符號的字母存在“亂序”的情況:
alert( 'Österreich' > 'Zealand' ); // true
如果我們對這些國家名進行排序,可能會導致奇怪的結果。通常,人們會期望 Zealand
在名單中的 Österreich
之後出現。
爲了明白發生了什麽,我們回顧壹下在 JavaScript 中字符串的內部表示。
所有的字符串都使用 UTF-16 編碼。即:每個字符都有對應的數字代碼。有特殊的方法可以獲取代碼表示的字符,以及字符對應的代碼。
str.codePointAt(pos)
返回在 pos
位置的字符代碼 :
// 不同的字母有不同的代碼 alert( "z".codePointAt(0) ); // 122 alert( "Z".codePointAt(0) ); // 90
String.fromCodePoint(code)
通過數字 code
創建字符
alert( String.fromCodePoint(90) ); // Z
我們還可以用 u
後跟十六進制代碼,通過這些代碼添加 Unicode 字符:
// 在十六進制系統中 90 爲 5a alert( 'u005a' ); // Z
現在我們看壹下代碼爲 65..220
的字符(拉丁字母和壹些額外的字符),方法是創建壹個字符串:
let str = ''; for (let i = 65; i <= 220; i++) { str += String.fromCodePoint(i); } alert( str ); // ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~ // ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜ
看到沒?先是大寫字符,然後是壹些特殊字符,然後是小寫字符,而 Ö
幾乎是最後輸出。
現在很明顯爲什麽 a > Z
。
字符通過數字代碼進行比較。越大的代碼意味著字符越大。a
(97)的代碼大于 Z
(90)的代碼。
所有小寫字母追隨在大寫字母之後,因爲它們的代碼更大。
壹些像 Ö
的字母與主要字母表不同。這裏,它的代碼比任何從 a
到 z
的代碼都要大。
執行字符串比較的“正確”算法比看起來更複雜,因爲不同語言的字母都不相同。
因此浏覽器需要知道要比較的語言。
幸運的是,所有現代浏覽器(IE10- 需要額外的庫 Intl.JS) 都支持國際化標准 ECMA-402。
它提供了壹種特殊的方法來比較不同語言的字符串,遵循它們的規則。
調用 str.localeCompare(str2) 會根據語言規則返回壹個整數,這個整數能指示字符串 str
在排序順序中排在字符串 str2
前面、後面、還是相同:
如果 str
排在 str2
前面,則返回負數。
如果 str
排在 str2
後面,則返回正數。
如果它們在相同位置,則返回 0
。
例如:
alert( 'Österreich'.localeCompare('Zealand') ); // -1
這個方法實際上在 文檔 中指定了兩個額外的參數,這兩個參數允許它指定語言(默認語言從環境中獲取,字符順序視語言不同而不同)並設置諸如區分大小寫,或應該將 "a"
和 "á"
作相同處理等附加的規則。
進階內容
這部分會深入字符串內部。如果妳計劃處理 emoji、罕見的數學或象形文字或其他罕見的符號,這些知識會對妳有用。
如果妳不打算支持它們,妳可以跳過這壹部分。
所有常用的字符都是壹個 2 字節的代碼。大多數歐洲語言,數字甚至大多數象形文字中的字母都有 2 字節的表示形式。
但 2 字節只允許 65536 個組合,這對于表示每個可能的符號是不夠的。所以稀有的符號被稱爲“代理對”的壹對 2 字節的符號編碼。
這些符號的長度是 2
:
alert( '?'.length ); // 2,大寫數學符號 X alert( '?'.length ); // 2,笑哭表情 alert( '?'.length ); // 2,罕見的中國象形文字
注意,代理對在 JavaScript 被創建時並不存在,因此無法被編程語言正確處理!
我們實際上在上面的每個字符串中都有壹個符號,但 length
顯示長度爲 2
。
String.fromCodePoint
和 str.codePointAt
是幾種處理代理對的少數方法。它們最近才出現在編程語言中。在它們之前,只有 String.fromCharCode 和 str.charCodeAt。這些方法實際上與 fromCodePoint/codePointAt
相同,但是不適用于代理對。
獲取符號可能會非常麻煩,因爲代理對被認爲是兩個字符:
alert( '?'[0] ); // 奇怪的符號…… alert( '?'[1] ); // ……代理對的壹塊
請注意,代理對的各部分沒有任何意義。因此,上述示例中的 alert 顯示的實際上是垃圾信息。
技術角度來說,代理對也是可以通過它們的代碼檢測到的:如果壹個字符的代碼在 0xd800..0xdbff
範圍內,那麽它是代理對的第壹部分。下壹個字符(第二部分)必須在 0xdc00..0xdfff
範圍中。這些範圍是按照標准專門爲代理對保留的。
在上述示例中:
// charCodeAt 不理解代理對,所以它給出了代理對的代碼 alert( '?'.charCodeAt(0).toString(16) ); // d835,在 0xd800 和 0xdbff 之間 alert( '?'.charCodeAt(1).toString(16) ); // dcb3, 在 0xdc00 和 0xdfff 之間
本章節後面的 Iterable object(可叠代對象) 章節中,妳可以找到更多處理代理對的方法。可能有專門的庫,這裏沒有什麽足夠好的建議了。
在許多語言中,都有壹些由基本字符組成的符號,在其上方/下方有壹個標記。
例如,字母 a
可以是 àáâäãåā
的基本字符。最常見的“複合”字符在 UTF-16 表中都有自己的代碼。但不是全部,因爲可能的組合太多。
爲了支持任意組合,UTF-16 允許我們使用多個 Unicode 字符:基本字符緊跟“裝飾”它的壹個或多個“標記”字符。
例如,如果我們 S
後跟有特殊的 “dot above” 字符(代碼 u0307
),則顯示 Ṡ。
alert( 'Su0307' ); // Ṡ
如果我們需要在字母上方(或下方)添加額外的標記 —— 沒問題,只需要添加必要的標記字符即可。
例如,如果我們追加壹個字符 “dot below”(代碼 u0323
),那麽我們將得到“S 上面和下面都有點”的字符:Ṩ
。
例如:
alert( 'Su0307u0323' ); // Ṩ
這在提供良好靈活性的同時,也存在壹個有趣的問題:兩個視覺上看起來相同的字符,可以用不同的 Unicode 組合表示。
例如:
let s1 = 'Su0307u0323'; // Ṩ,S + 上點 + 下點 let s2 = 'Su0323u0307'; // Ṩ,S + 下點 + 上點 alert( `s1: ${s1}, s2: ${s2}` ); alert( s1 == s2 ); // false,盡管字符看起來相同(?!)
爲了解決這個問題,有壹個 “Unicode 規範化”算法,它將每個字符串都轉化成單個“通用”格式。
它由 str.normalize() 實現。
alert( "Su0307u0323".normalize() == "Su0323u0307".normalize() ); // true
有趣的是,在實際情況下,normalize()
實際上將壹個由 3 個字符組成的序列合並爲壹個:u1e68
(S 有兩個點)。
alert( "Su0307u0323".normalize().length ); // 1 alert( "Su0307u0323".normalize() == "u1e68" ); // true
事實上,情況並非總是如此,因爲符號 Ṩ
是“常用”的,所以 UTF-16 創建者把它包含在主表中並給它了對應的代碼。
如果妳想了解更多關于規範化規則和變體的信息 —— 它們在 Unicode 標准附錄中有詳細描述:Unicode 規範化形式,但對于大多數實際目的來說,本文的內容就已經足夠了。
有 3 種類型的引號。反引號允許字符串跨越多行並可以使用 ${…}
在字符串中嵌入表達式。
JavaScript 中的字符串使用的是 UTF-16 編碼。
我們可以使用像 n
這樣的特殊字符或通過使用 u...
來操作它們的 Unicode 進行字符插入。
獲取字符時,使用 []
。
獲取子字符串,使用 slice
或 substring
。
字符串的大/小寫轉換,使用:toLowerCase/toUpperCase
。
查找子字符串時,使用 indexOf
或 includes/startsWith/endsWith
進行簡單檢查。
根據語言比較字符串時使用 localeCompare
,否則將按字符代碼進行比較。
還有其他幾種有用的字符串方法:
str.trim()
—— 刪除字符串前後的空格 (“trims”)。
str.repeat(n)
—— 重複字符串 n
次。
……更多內容細節請參見 手冊。
字符串還具有使用正則表達式進行搜索/替換的方法。但這個話題很大,因此我們將在本教程中單獨的 正則表達式 章節中進行討論。
重要程度: 5
寫壹個函數 ucFirst(str)
,並返回首字母大寫的字符串 str
,例如:
ucFirst("john") == "John";
打開帶有測試的沙箱。
我們不能“替換”第壹個字符,因爲在 JavaScript 中字符串是不可變的。
但是我們可以根據已有字符串創建壹個首字母大寫的新字符串:
let newStr = str[0].toUpperCase() + str.slice(1);
這裏存在壹個小問題。如果 str
是空的,那麽 str[0]
就是 undefined
,但由于 undefined
並沒有 toUpperCase()
方法,因此我們會得到壹個錯誤。
存在如下兩種變體:
使用 str.charAt(0)
,因爲它總是會返回壹個字符串(可能爲空)。
爲空字符添加測試。
這是第二種變體:
function ucFirst(str) { if (!str) return str; return str[0].toUpperCase() + str.slice(1); } alert( ucFirst("john") ); // John
使用沙箱的測試功能打開解決方案。
重要程度: 5
寫壹個函數 checkSpam(str)
,如果 str
包含 viagra
或 XXX
就返回 true
,否則返回 false
。
函數必須不區分大小寫:
checkSpam('buy ViAgRA now') == true checkSpam('free xxxxx') == true checkSpam("innocent rabbit") == false
打開帶有測試的沙箱。
爲了使搜索不區分大小寫,我們將字符串改爲小寫,然後搜索:
function checkSpam(str) { let lowerStr = str.toLowerCase(); return lowerStr.includes('viagra') || lowerStr.includes('xxx'); } alert( checkSpam('buy ViAgRA now') ); alert( checkSpam('free xxxxx') ); alert( checkSpam("innocent rabbit") );
使用沙箱的測試功能打開解決方案。
重要程度: 5
創建函數 truncate(str, maxlength)
來檢查 str
的長度,如果超過 maxlength
—— 應使用 "…"
來代替 str
的結尾部分,長度仍然等于 maxlength
。
函數的結果應該是截斷後的文本(如果需要的話)。
例如:
truncate("What I'd like to tell on this topic is:", 20) = "What I'd like to te…" truncate("Hi everyone!", 20) = "Hi everyone!"
打開帶有測試的沙箱。
最大長度必須是 maxlength
,因此爲了給省略號留空間我們需要縮短它。
請注意,省略號實際上有壹個單獨的 Unicode 字符,而不是三個點。
function truncate(str, maxlength) { return (str.length > maxlength) ? str.slice(0, maxlength - 1) + '…' : str; }
使用沙箱的測試功能打開解決方案。
重要程度: 4
我們有以 "$120"
這樣的格式表示的花銷。意味著:先是美元符號,然後才是數值。
創建函數 extractCurrencyValue(str)
從字符串中提取數值並返回。
例如:
alert( extractCurrencyValue('$120') === 120 ); // true
打開帶有測試的沙箱。
function extractCurrencyValue(str) { return +str.slice(1); }
使用沙箱的測試功能打開解決方案。