JavaScript中的String.replace(a, b)函数默认是只执行一次替换,即在某个字符串中检索a子串,然后再用b来替换a,只执行一次这样的操作,即使后面跟着多个a,它也不会继续往后面检索,其实我这么说是不正确的,准确的理解大家可以查看
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/replace
看看replace方法的参数就明白了
但是如果大家没有注意这个函数的说明,就很容易认为这个函数有类似于replaceAll这样的功能,并且默认是具有这样的功能的
并且还有人为此付出过代价
所以说Gareth Heyes才说这个方法是Bad Design
http://www.thespanner.co.uk/2010/09/27/string-replace-javascript-bad-design/
并且给了个这个函数的patch版本,默认是执行全文替换
其实我觉得一定要开发人员清楚函数的功能这样才不容易犯错,即使默认执行的是全文替换,在有些不需要全文替换的情况下还是有人会出错
不过既然给出patch了,作为菜鸟慢慢飞的我还是想看下,做事总会有理由的,否则人家吃力不讨好,何必呢。
下面是作者的代码,我只是COPY过来了,在看的时候不懂了,希望看到这里的人指点指点小弟啦,后面会有问题
String.prototype.replace = (function(r){
return function(find, replace, replaceOnce) {
if(typeof find == 'string' && !replaceOnce) {
find = r.apply(find, [/[\[\]^$*+.?(){}\\\-]/g,function(c) { return '\\'+c; }]);
find = new RegExp(find, 'g');
} else if(typeof find == 'object' && !replaceOnce && !find.global) {
find = new RegExp(find.source, 'g');
}
return r.apply(this, [find,replace]);
};
})(String.prototype.replace);
函数使用样例,照搬过来的
alert('aaaabbbbb'.replace(/a/,''))
利用把匿名函数执行结果赋值给一个引用变量的方式来定义一个函数,这里就相当于它把原来的replace函数给覆盖了
实际后面的匿名函数返回了一个函数,该函数可以接受三个参数,比较清楚
现在我们把这个函数分解掉,只拿出关键的部分,即:
function(find, replace, replaceOnce) {
if(typeof find == 'string' && !replaceOnce) {
find = r.apply(find, [/[\[\]^$*+.?(){}\\\-]/g,function(c) { return '\\'+c; }]);
find = new RegExp(find, 'g');
} else if(typeof find == 'object' && !replaceOnce && !find.global) {
find = new RegExp(find.source, 'g');
}
return r.apply(this, [find,replace]);
};
这个当中的r实际上就是String.prototype.replace,即原生态的replace函数
这个函数有两个if,实际上会有三种情况
第一:当传入的要被替换的东西是字符串,并且没有明确指出只替换一次的时候,它执行全文替换,即替换所有出现find的地方
第二:当传入的是对象(实际上这个对象已经基本确认为正则表达式对象,所以才会有后面的global属性),并且没有明确指出只替换一次的时候,并且该对象的global属性也没有为true的时候,即替换所有出现find的地方
第三:其他情况替换第一次出现的find(默认功能)
从这里开始我就不是很清楚了
这里它是在替换之前对find进行了一些处理,我们继续分解
第一种情况,这里出现了一个数组参数,分别是个正则表达式和一个函数
我们只看这个正则表达式的意思
我的理解是对find参数中的遇到的这些东西/
[\[\]^$*+.?(){}\\\-]/进行全文替换
OMG,一个参数中会有这么复杂的情况吗?
誰能帮我解释解释这个正则表达式的含义啊,万分感谢
只要能把这个搞明白后面的就很简单了
第二种情况,这里用了typeof来侦测find的类型,这里又引申出来另外一个东西
typeof(正则表达式对象),这个会返回什么?
我简单做了下测试,结果如下
引用
// IE8 object
// FF3.6 object
// Opera9.26 object
// Chromium4.0 function
// jsdb function
但是,typeof(正则表达式对象) == "object",这个又会是什么?
同样简单测试:
引用
// IE8 true
// FF3.6 true
// Opera9.26 true
// Chromium4.0 true
// jsdb false
唯一一个出现false的东西,它不是浏览器,还好
为什么Chromium4.0在这个问题上步调不一致呢
然后我又测试了另外一个问题,typeof(/a/) == "function"
在Chromium4.0 上返回false,我下我就糊涂了
难道跟Chromium的JS引擎和正则表达式引擎有关,等待高人指点一二
看来这应当是bug
第三种情况,没啥好说的,就是默认的情况
到这里就剩下一个正则和一个typeof(正则)弄不明白了
其中这个正则表达式,我还试着继续分解了下,发现弄不下去了
/[\[\]^$*+.?(){}\\\-]/g
[\[\]^$*+.?(){}\\\-]
下面任意一种情况出现
[
]
...
后面的我两眼一绿,就分不出来了
后来又用工具测了下,让我又晕了会
实际上我觉得这里前后的“/”和“/g”本来就应当是匹配所有,即传入的参数中如果包括下面的任意字符
引用
[
]
^
$
*
+
.
?
(
)
{
}
\
-
都会被转义成普通字符,而不是正则表达式当中的元字符,从而构造新的正则表达式
RegexBuddy 写道
Match the character “/” literally
Match a single character present in the list below
A [ character
A ] character
One of the characters “^$*+.?(){}”
A \ character
A - character
Match the characters “/g” literally
RegexBuddy(The Regex Coach)里面分析出来的前后“/”和“/g”,它直接把认为是普通字符了,让我有点迷糊,可能跟工具本身具有的功能相关(工具已经具有可以选择是否忽略大小写,全局匹配,多行匹配这些功能,所以它直接把这些表达式文字上写的这些特殊符号当成普通字符了)
现在总算是明白这段正则的含义和用途了
P.S. Irregexp
The Regex Coach和RegexBuddy都是我在使用的正则表达式工具,RegexBuddy似乎更强大