字符串的replace()方法隱藏着什么不可告人秘密?


最近在做JS算法項目時發現一個令我匪夷所思的問題, 這里想記錄一下問題。

首先介紹一下字符串replace()方法的基本用法。

replace() 方法使用一個替換值(replacement)替換掉一個匹配模式(pattern)在原字符串中某些或所有的匹配項,並返回替換后的字符串。這個替換模式可以是字符串或者RegExp(正則表達式),替換值可以是一個字符串或者一個函數。

語法EDIT

str.replace(regexp|substrnewSubStr|function[, flags])

參數

regexp
一個  RegExp 對象。該正則所匹配的內容會被第二個參數的返回值替換掉。
substr
一個要被  newSubStr  替換的字符串。
newSubStr
替換掉第一個參數在原字符串中的匹配部分。該字符串中可以內插一些特殊的變量名。
function

一個用來創建新子字符串的函數,該函數的返回值將替換掉第一個參數匹配到的結果。該函數的參數描述請參考 指定一個函數作為參數 小節。

返回值

一個部分或全部匹配由替代模式所取代的新的字符串。

關於這個方法具體的信息參考MDN再好不過了。

String.prototype.replace() - JavaScript | MDN

 

現在有一個非常簡單的需求:將HTML代碼中的特殊字符進行實體轉義:

先看一個簡單的輸出沒有錯誤的版本:

正確方法一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function convertHTML(str) {
   // :)
   var pattern=/[&<> "']/g;
   return str.replace(pattern,function(match){
     switch(match){
         case " < ":
         return " &lt; ";
         case " > ":
         return " &gt; ";
         case " & ":
         return " &amp; ";
         case " \ "" :
         return "&quot;" ;
         case "\'" :
         return "&apos;" ;
     }
   });
}
console.log(convertHTML( "<Tom & Jerry>" ));//&lt;Tom &amp; Jerry&gt;

指定一個函數作為第二個參數。在這種情況下,當匹配執行后, 該函數就會執行。 函數的返回值作為替換字符串。 (注意:  上面提到的特殊替換參數在這里不能被使用。) 另外要注意的是, 如果第一個參數是正則表達式, 並且其為全局匹配模式, 那么這個方法將被多次調用, 每次匹配都會被調用。

后來我對上述的代碼進行了改造,使代碼看起來更明了:

正確方法二:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
function convertHTML(str) {
   // &colon;&rpar;
   var pattern=/[&<> "']/g;
   rules={" & ":" &amp; "," < ":" &lt; "," > ":" &gt; ",'" ':"&quot;","' ": "&apos;" };
  return str.replace(pattern, function (match){
     return  rules[match];
   });
 
 
}
console.log(convertHTML( "<Tom & Jerry>" ));//&lt;Tom &amp; Jerry&gt;

很明顯非常簡單的一個改造,我將規則鍵值對放在了rules對象中,輸出結果同樣也是正確的。

接下來,我發現貌似使用RegExp構造函數屬性還能使代碼變得更加簡單。RegExp構造函數屬性如下表所示:

其中一個叫做lastMatch的屬性深深吸引了我。我在想能不能像下面這樣改造一下:

錯誤方法:

1
2
3
4
5
6
function convertHTML(str) {
   var pattern=/[&<> "']/g;
   rules={" & ":" &amp; "," < ":" &lt; "," > ":" &gt; ",'" ':"&quot;","' ": "&apos;" };
   return str.replace(pattern,rules[RegExp.lastMatch]);
}
console.log(convertHTML( "<Tom & Jerry>" ));

寫完這個代碼,突然覺得自己聰明絕世,飄飄然了呢,然而一瓢冷水潑下來了。運行結果如下:

 

 
1
undefinedTom undefined Jerryundefined

這是什么鬼,貌似該替換的字符都被替換成了undefined。接下來我加入了一條測試語句:

 

 

 
1
2
3
4
5
6
7
8
9
function convertHTML(str) {
   // &colon;&rpar;
   var pattern=/[&<> "']/g;
   rules={" & ":" &amp; "," < ":" &lt; "," > ":" &gt; ",'" ':"&quot;","' ": "&apos;" };

  var result=str.replace(pattern,rules[RegExp.lastMatch]);

//下面是測試代碼

   console.log(RegExp.lastMatch);//>
   return result;
}
console.log(convertHTML( "<Tom & Jerry>" ));

根據測試代碼,最后匹配的是“>”說明匹配是正確的,但是最后為什么沒有按照規則進行替換呢,我想應該是replace()方法的實現機制我們沒有弄清楚,網上沒有找到相關的資料,所以只能提醒自己以后不能寫這樣的代碼了,在這種情況下,還是乖乖函數作為第二個參數。。。。。。等等,用函數做第二個參數,我又進行了下面的修改:

1
2
3
4
5
6
7
8
9
10
function convertHTML(str) {
   // &colon;&rpar;
   var pattern=/[&<> "']/g;
   rules={" & ":" &amp; "," < ":" &lt; "," > ":" &gt; ",'" ':"&quot;","' ": "&apos;" };
   var result=str.replace(pattern, function (){
     return rules[RegExp.lastMatch]
   });
   return result;
}
console.log(convertHTML( "<Tom & Jerry>" )); //&lt;Tom &amp; Jerry&gt;

注意上面我還是使用了正則表達式函數屬性與方法二是有區別的,但是結果卻是離奇的正確了。(難道閉包作怪)

 

 

replace()究竟隱藏着什么秘密,還有待挖掘??




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM