本文深入探讨JavaScript中split与join函数的进阶应用。通过这两个核心方法的组合,可以实现全局字符串替换、子串计数、重复字符串生成以及数组成员批量修改等功能。文章还对比了不同浏览器下的性能表现,并提供了针对IE兼容性的修正方案,帮助开发者更高效地处理字符串与数组的转换逻辑。
split与join函数基础介绍
JavaScript提供了两个功能强大且深受开发者青睐的方法:split与join。这两个互为逆操作的方法实现了String与Array两种数据类型的相互转换,即数组可以序列化为字符串,字符串也可以分割为数组。充分发挥这两个方法的潜力,可以解决许多复杂的字符串处理问题。接下来我们将介绍这两个方法的基本定义。
String.prototype.split(separator, limit) separator参数用于将字符串分割成数组,可选参数limit用于限制生成数组的最大长度。
"85@@86@@53".split('@@'); //['85','86','53'];
"banana".split(); //["banana"]; //( thanks peter (-: )
"president,senate,house".split(',',2); //["president", "senate"]
Array.prototype.join(separator)
可选参数separator用于将数组转换为字符串。如果未提供该参数,默认使用逗号作为分隔符(这与数组的toString方法行为一致)。
["slugs","snails","puppy dog's tails"].join(' and '); //"slugs and snails and puppy dog's tails"
['Giants', 4, 'Rangers', 1].join(' '); //"Giants 4 Rangers 1"
[1962,1989,2002,2010].join();
split与join的进阶应用
下面展示这些方法在实际场景中的应用:
replaceAll 这个简单的函数实现了全局子字符串替换的功能,与原生replace方法不同,它不需要使用正则表达式。
String.prototype.replaceAll = function(find, replaceWith) {
return this.split(find).join(replaceWith);
}
"the man and the plan".replaceAll('the','a'); //"a man and a plan"
对于较短的字符串,其性能可能略低于单次字符替换的原生函数(这里涉及正则表达式的额外开销)。但在Mozilla浏览器中,当替换字符超过2或3个字符时,这种方法的运行速度反而比正则表达式更快。
occurences 该方法用于获取子字符串匹配的数量。其实现逻辑直观,无需依赖正则表达式。
String.prototype.occurences = function(find, matchCase) {
var text = this;
matchCase || (find = find.toLowerCase(), text = text.toLowerCase());
return text.split(find).length-1;
}
document.body.innerHTML.occurences("div"); //google home page has 114
document.body.innerHTML.occurences("/div"); //google home page has 57
"England engages its engineers".occurrences("eng",true); //2
repeat
该函数的灵感来源于prototype.js:
String.prototype.repeat = function(times) {
return new Array(times+1).join(this);
}
"go ".repeat(3) + "Giants!"; //"go go go Giants!"
其精妙之处在于对join方法的巧妙运用。关键点在于separator参数的值,而基础数组仅包含未定义的值。为了更清晰地说明这一点,我们重新构造上述示例:
[undefined,undefined,undefined,undefined].join("go ") + "Giants
需要注意的是,在调用join之前,每个数组元素都会转换为字符串(此处为空字符串)。利用数组字面量定义数组是应用repeat函数的少数可行方式之一。
利用limit参数优化处理
使用limit参数 我很少使用split方法的limit可选参数,下面介绍一个使用该参数的实例:
var getDomain = function(url) {
return url.split('/',3).join('/');
}
getDomain("http://www.aneventapart.com/2010/seattle/slides/");
//"http://www.aneventapart.com"
getDomain("https://addons.mozilla.org/en-US/firefox/bookmarks/");
//"https://addons.mozilla.org"
修改数值成员 如果结合正则表达式使用,join和split可以轻松地修改数组成员。虽然这个函数看起来并不复杂,但其主要功能是去除给定数组中每个成员前面指定的字符串。
var beheadMembers = function(arr, removeStr) {
var regex = RegExp("[,]?" + removeStr);
return arr.join().split(regex).slice(1);
}
//make an array containing only the numeric portion of flight numbers
beheadMembers(["ba015","ba129","ba130"],"ba"); //["015","129","130"]
不幸的是,这种函数在IE浏览器中会失效,因为它们错误地从split结果中去掉了第一个空成员。现在我们来修正这个函数:
var beheadMembers = function(arr, removeStr) {
var regex = RegExp("[,]?" + removeStr);
var result = arr.join().split(regex);
return result[0] && result || result.slice(1); //IE workaround
}
我们为什么要使用这种技巧,而不是使用EcmaScript 5中引入的array的map函数呢?
["ba015","ba129","ba130"].map(function(e) {
return e.replace('ba','')
}); //["015","129","130"]
在实际开发中,只要条件允许,我通常优先使用原生的map函数(在IE9以下版本中不可用)。下面的例子仅作为学习工具,但值得注意的是,join与split的调用语法更加简洁直接。最有趣的是,这种方法也非常高效,尤其是对于小数组,在FF与Safari中表现更为优异。对于大数组,map函数则更为合适(在所有浏览器中),因为join与split的函数调用次数较少。
//test 1 - using join/split
var arr = [], x = 1000;
while (x--) {arr.push("ba" + x);}
var beheadMembers = function(arr, regex) {
return arr.join().split(regex).slice(1);
}
var regex = RegExp("[,]?" + 'ba');
var timer = +new Date, y = 1000;
while(y--) {beheadMembers(arr,regex);};
+new Date - timer;
//FF 3.6 733ms
//Ch 7 464ms
//Sa 5 701ms
//IE 8 1256ms
//test 2 - using native map function
var arr = [], x = 1000;
while (x--) {arr.push("ba" + x);}
var timer = +new Date, y = 1000;
while(y--) {
arr.map(function(e) {
return e.replace('ba','')
});
}
+new Date - timer;
//FF 3.6 2051ms
//Cr 7 732ms
//Sf 5 1520ms
//IE 8 (Not supported)
数组与字符串的模式匹配
模式匹配 数组需要不断执行模式匹配,而字符串本身不会。正则表达式可以在字符串中应用,但在数组中则不行。将数组转换为字符串进行模式匹配的强大之处远远超出了本文的讲述范围。让我们来看一个简单的应用。
假设竞走比赛的结果需要保存到数组中。目的是将竞赛者与他们的记录时间交替地放在数组中。我们可以用join与正则表达式来验证这种存储模式是否正确。下面的代码通过查找两个连续的名字来找出记录时间被漏掉的情况。
var results = ['sunil', '23:09', 'bob', '22:09', 'carlos', 'mary', '22:59'];
var badData = results.join(',').match(/[a-zA-Z]+,[a-zA-Z]+/g);
badData; //["carlos,mary"]