JavaScript字符串String和Array操作的有趣方法
更新時(shí)間:2012年12月18日 16:56:49 作者:
字符串和數(shù)組在程序編寫(xiě)過(guò)程中是十分常用的類(lèi)型,因此程序語(yǔ)言都會(huì)將String和Array作為基本類(lèi)型,并提供許多字符串和數(shù)組的方法來(lái)簡(jiǎn)化對(duì)字符串的操作
字符串和數(shù)組在程序編寫(xiě)過(guò)程中是十分常用的類(lèi)型,因此程序語(yǔ)言都會(huì)將String和Array作為基本類(lèi)型,并提供許多字符串和數(shù)組的方法來(lái)簡(jiǎn)化對(duì)字符串的操作。JavaScript里面也提供了String類(lèi)型和Array類(lèi)型,并且有很多基本的String方法和Array方法來(lái)方便地對(duì)字符串進(jìn)行合并、查找、替換、截取等處理。
JavaScript作為一個(gè)腳本語(yǔ)言,又提供了一種動(dòng)態(tài)解析運(yùn)行的機(jī)制,而這特性,又讓使得在String操作的時(shí)候出現(xiàn)一些結(jié)合使用Array的有趣方法。這些方法可能有些偏門(mén)有點(diǎn)奇怪,但有時(shí)在效率、可讀性、復(fù)用性上表現(xiàn)得卻更好。
重復(fù)字符串
常常我們想要把字符串多次打印出來(lái)(比如想要個(gè)分割線),我們就需要將一個(gè)字符串重復(fù)多次, 可惜JavaScript并沒(méi)有提供類(lèi)似repeat這樣的方法。當(dāng)然我們可以用循環(huán)來(lái)拼接出來(lái),但是我們可以利用JavaScript中Array的join方法來(lái)實(shí)現(xiàn)repeat
function repeat(str, n) {
var arr = new Array(n+1);
return arr.join(str);
}
//output:
//-------
利用n+1個(gè)Array元素產(chǎn)生的n個(gè)間隙,再以目標(biāo)字符串來(lái)拼接,我們就能得到字符串重復(fù)的功能。
擴(kuò)展String的prototype使方法應(yīng)用于所有字符串
JavaScript的對(duì)象繼承和方法尋找是基于原型鏈(prototype chain),所有使用著的字符串都可以說(shuō)是繼承于String的對(duì)象,我們可以為String對(duì)象的prototype添加方法或者屬性,這樣該方法就可以應(yīng)用到所有我們使用的對(duì)象上了。比如上邊的repeat方法,就可以改成:
String.prototype.repeat = function(n) {
var arr = new Array(n+1);
return arr.join(this);
};
document.write('-'.repeat(21));
//output:
//---------------------
然后,直接通過(guò)字符串調(diào)用repeat方法,就可以得到跟上邊一樣的結(jié)果。
這可以讓我們實(shí)現(xiàn)對(duì)字符串方法的擴(kuò)充,簡(jiǎn)潔對(duì)字符串的操作,但是這會(huì)“污染”了JavaScript的String,當(dāng)代碼被轉(zhuǎn)到其他文件但是那個(gè)文件下并沒(méi)有得到這段擴(kuò)充,就可能會(huì)造成找不到該方法;另外,調(diào)用prototype擴(kuò)展方法比直接調(diào)用方法要稍微“慢”一些,因?yàn)镴avaScript會(huì)先去在字符串對(duì)象自身的方法中嘗試尋找,再找到String的prototype的方法;再者也許在將來(lái)我們擴(kuò)充的方法(比如repeat)變成了標(biāo)準(zhǔn)方法了,再使用這代碼就會(huì)覆蓋了標(biāo)準(zhǔn)方法,得到不一致的結(jié)果。
但是忽略這些考慮,擴(kuò)充JavaScript標(biāo)準(zhǔn)類(lèi)型的prototype還是會(huì)給編程帶來(lái)許多的遍歷。
用Array作StringBuilder
在很多高級(jí)語(yǔ)言中,加號(hào)(+)在字符串的操作中被賦予了更多的意義:作為字符串拼接的操作符。不過(guò)在Java和C#中,我們也知道如何頻繁進(jìn)行字符串拼接的操作,使用加號(hào)(+)就會(huì)產(chǎn)生效率問(wèn)題,因此在這種情況下就會(huì)推薦使用StringBuilder。
JavaScript也支持使用加號(hào)(+)來(lái)進(jìn)行字符串拼接,那么也會(huì)有存在效率問(wèn)題呢??墒荍avaScript并沒(méi)有提供StringBuilder這樣的類(lèi)。
其實(shí)在Java,C#中使用StringBuilder時(shí),我們多數(shù)也是用append方法,而很少會(huì)用insert。好在JavaScript的Array是不限大小自動(dòng)增長(zhǎng)的,所以我們就可以利用Array來(lái)做StringBuilder,最后再join空字符串來(lái)拼接出目標(biāo)字符串。
var sb = [];
for(var i = 0; i <=21; i++) {
sb.push(i);
}
document.write(sb.join(''));
//output:
//0123456789101112131415161718192021
到底是用Array做StringBuilder還是直接字符串拼接,jsPerf上有過(guò)很多testcases比較兩者的效率,但是因?yàn)槌跏贾?、環(huán)境、字符串長(zhǎng)度等原因,所以結(jié)果不一。其實(shí)字符串內(nèi)容不是很大,或者可以使用多個(gè)加號(hào)(+)組合在一起,那么字符串拼接還是可以的;若是在代碼不同地方對(duì)同一字符串變量進(jìn)行追加,那么可能使用Array配合join會(huì)更好。
用split替代字符串的子串查找和替換
在字符串的操作中,很常出現(xiàn)的就是想要從字符串中查找一個(gè)子字符串是否存在,然后截取出該字符串,抑或是將該子字符串替換成其它字符串。
比如給一個(gè)文件名,希望根據(jù)點(diǎn)(.)分割獲取基本名和后綴名。先來(lái)看看使用標(biāo)準(zhǔn)String方法實(shí)現(xiàn)的這些操作:
function getBaseName(str) {
var pos = str.lastIndexOf('.');
if(pos < 0)return str;
return str.substring(0, pos);
}
function getExtension(str) {
var pos = str.lastIndexOf('.');
if(pos < 0)return '';
return str.substr(pos+1);
}
var fileName = 'hello_world.js';
document.write(getBaseName(fileName));
document.write('<br />');
document.write(getExtension(fileName));
//output:
//hello_world
//js
(除了substr和substring外,JavaScript還有slice都可以用來(lái)獲取字符串的子串,但也正是因?yàn)檫x擇太多,常常讓我在出現(xiàn)選擇恐慌,還有位置是該不該+1,對(duì)負(fù)數(shù)是如何處理也讓我揪心。)
之前看到可以通過(guò)join把數(shù)組變成字符串,也可以利用String的split的方法把字符串變成數(shù)組。對(duì)于上邊取文件名及擴(kuò)展名的問(wèn)題,我們就可以根據(jù)“.”把文件名分裂成數(shù)組各個(gè)部分,那么假如得到的數(shù)字大于1(后綴名存在),則所得數(shù)字的最后一個(gè)元素就是文件的擴(kuò)展名了:
function getBaseName(str) {
var segs = str.split('.');
if(segs.length > 1) segs.pop();
return segs.join('.');
}
function getExtension(str) {
var segs = str.split('.');
if(segs.length <= 1)return '';
return segs.pop();
}
考慮到文件名中可能包含多個(gè)“.”,所以我們還是需要用“.”把除了最后一部分外的各個(gè)部分join回來(lái)。
看到可以對(duì)字符串先split再join,就可以想到,我們可以想到對(duì)于這兩個(gè)方法的參數(shù)可以傳入不同的字符串,這樣就起到了代替String的replace方法進(jìn)行子串替換的功能了,而且還是全局替換。
比如希望把所有的下劃線(_)替換成橫杠(-):
var str = 'hello_from_ider_to_world'.split('_').join('-');
document.write(str);
//Output:
// hello-from-ider-to-world
相對(duì)于String的replace方法,該方法的有點(diǎn)在于:可以實(shí)現(xiàn)全局替換;而若要讓replace能夠全局替換,則需要傳入正則表達(dá)式對(duì)象(RegExp)而不能是字符串作為第一參數(shù)。
replace可接受RegExp、Function作為參數(shù)
很多人知道String的replace方法是用來(lái)替換字符串子串的,也可能知道它可以接受正則表達(dá)式作為第一參數(shù),而且如何要替換所有出現(xiàn)的地方,就必須要用RegExp并包含global標(biāo)記。
比如之前的替換操作,用replace就應(yīng)該是:
var str = 'hello_from_ider_to_world'.replace(/_/g, '-');
document.write(str);
再比如很常用的trim方法,雖然JavaScript并沒(méi)有提供我們也可以自己很快的實(shí)現(xiàn):
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, '');
};
我們知道正則表達(dá)式一個(gè)很強(qiáng)大的功能就是向后引用(Back Reference),實(shí)際上JavaScript的replace不僅在第一個(gè)參數(shù)內(nèi)做向后引用,而且在替換字符串上,也可以進(jìn)行向后引用,只是很多地方可能用反斜杠(\)加數(shù)字作為標(biāo)示而JavaScript則是用美刀($)加數(shù)字作為標(biāo)示。
var friends = 'friends of Ider, friend of Angie';
var result = friends.replace(/(friends?) of (\w+)/g, "$2's $1");
document.write(result);
//output:
//Ider's friends, Angie's friend
通過(guò)在替換字符串里面進(jìn)行向后引用,我們很快就把“朋友 of 誰(shuí)誰(shuí)誰(shuí)”變成了“誰(shuí)誰(shuí)誰(shuí)的朋友”。如果還要更復(fù)雜點(diǎn)怎么辦呢?沒(méi)有關(guān)系,replace還能接受Function作為參數(shù)作為回調(diào)函數(shù),其中函數(shù)的第一個(gè)參數(shù)是整個(gè)匹配中的字符串,之后每一個(gè)代表個(gè)個(gè)向后引用匹配的,函數(shù)的返回值則是作為替換的字符串。所以很多使用,函數(shù)參數(shù)都會(huì)用$0, $1, $2來(lái)表示。來(lái)看個(gè)例子:
var friends ="friends of mine, friend of her and friends of his";
var result = friends.replace(/(friends?) of (\w+)/g,
function($0, $1, $2) {
if($2 == 'mine') $2 = 'my';
return $2 + ' ' + $1;
});
document.write(result);
//output:
//my friends, her friend and his friends
通過(guò)回調(diào)函數(shù)就可以實(shí)現(xiàn)很多很負(fù)責(zé)的字符串匹配了。至于效率,就先不考慮了。
JavaScript作為一個(gè)腳本語(yǔ)言,又提供了一種動(dòng)態(tài)解析運(yùn)行的機(jī)制,而這特性,又讓使得在String操作的時(shí)候出現(xiàn)一些結(jié)合使用Array的有趣方法。這些方法可能有些偏門(mén)有點(diǎn)奇怪,但有時(shí)在效率、可讀性、復(fù)用性上表現(xiàn)得卻更好。
重復(fù)字符串
常常我們想要把字符串多次打印出來(lái)(比如想要個(gè)分割線),我們就需要將一個(gè)字符串重復(fù)多次, 可惜JavaScript并沒(méi)有提供類(lèi)似repeat這樣的方法。當(dāng)然我們可以用循環(huán)來(lái)拼接出來(lái),但是我們可以利用JavaScript中Array的join方法來(lái)實(shí)現(xiàn)repeat
復(fù)制代碼 代碼如下:
function repeat(str, n) {
var arr = new Array(n+1);
return arr.join(str);
}
//output:
//-------
利用n+1個(gè)Array元素產(chǎn)生的n個(gè)間隙,再以目標(biāo)字符串來(lái)拼接,我們就能得到字符串重復(fù)的功能。
擴(kuò)展String的prototype使方法應(yīng)用于所有字符串
JavaScript的對(duì)象繼承和方法尋找是基于原型鏈(prototype chain),所有使用著的字符串都可以說(shuō)是繼承于String的對(duì)象,我們可以為String對(duì)象的prototype添加方法或者屬性,這樣該方法就可以應(yīng)用到所有我們使用的對(duì)象上了。比如上邊的repeat方法,就可以改成:
復(fù)制代碼 代碼如下:
String.prototype.repeat = function(n) {
var arr = new Array(n+1);
return arr.join(this);
};
document.write('-'.repeat(21));
//output:
//---------------------
然后,直接通過(guò)字符串調(diào)用repeat方法,就可以得到跟上邊一樣的結(jié)果。
這可以讓我們實(shí)現(xiàn)對(duì)字符串方法的擴(kuò)充,簡(jiǎn)潔對(duì)字符串的操作,但是這會(huì)“污染”了JavaScript的String,當(dāng)代碼被轉(zhuǎn)到其他文件但是那個(gè)文件下并沒(méi)有得到這段擴(kuò)充,就可能會(huì)造成找不到該方法;另外,調(diào)用prototype擴(kuò)展方法比直接調(diào)用方法要稍微“慢”一些,因?yàn)镴avaScript會(huì)先去在字符串對(duì)象自身的方法中嘗試尋找,再找到String的prototype的方法;再者也許在將來(lái)我們擴(kuò)充的方法(比如repeat)變成了標(biāo)準(zhǔn)方法了,再使用這代碼就會(huì)覆蓋了標(biāo)準(zhǔn)方法,得到不一致的結(jié)果。
但是忽略這些考慮,擴(kuò)充JavaScript標(biāo)準(zhǔn)類(lèi)型的prototype還是會(huì)給編程帶來(lái)許多的遍歷。
用Array作StringBuilder
在很多高級(jí)語(yǔ)言中,加號(hào)(+)在字符串的操作中被賦予了更多的意義:作為字符串拼接的操作符。不過(guò)在Java和C#中,我們也知道如何頻繁進(jìn)行字符串拼接的操作,使用加號(hào)(+)就會(huì)產(chǎn)生效率問(wèn)題,因此在這種情況下就會(huì)推薦使用StringBuilder。
JavaScript也支持使用加號(hào)(+)來(lái)進(jìn)行字符串拼接,那么也會(huì)有存在效率問(wèn)題呢??墒荍avaScript并沒(méi)有提供StringBuilder這樣的類(lèi)。
其實(shí)在Java,C#中使用StringBuilder時(shí),我們多數(shù)也是用append方法,而很少會(huì)用insert。好在JavaScript的Array是不限大小自動(dòng)增長(zhǎng)的,所以我們就可以利用Array來(lái)做StringBuilder,最后再join空字符串來(lái)拼接出目標(biāo)字符串。
復(fù)制代碼 代碼如下:
var sb = [];
for(var i = 0; i <=21; i++) {
sb.push(i);
}
document.write(sb.join(''));
//output:
//0123456789101112131415161718192021
到底是用Array做StringBuilder還是直接字符串拼接,jsPerf上有過(guò)很多testcases比較兩者的效率,但是因?yàn)槌跏贾?、環(huán)境、字符串長(zhǎng)度等原因,所以結(jié)果不一。其實(shí)字符串內(nèi)容不是很大,或者可以使用多個(gè)加號(hào)(+)組合在一起,那么字符串拼接還是可以的;若是在代碼不同地方對(duì)同一字符串變量進(jìn)行追加,那么可能使用Array配合join會(huì)更好。
用split替代字符串的子串查找和替換
在字符串的操作中,很常出現(xiàn)的就是想要從字符串中查找一個(gè)子字符串是否存在,然后截取出該字符串,抑或是將該子字符串替換成其它字符串。
比如給一個(gè)文件名,希望根據(jù)點(diǎn)(.)分割獲取基本名和后綴名。先來(lái)看看使用標(biāo)準(zhǔn)String方法實(shí)現(xiàn)的這些操作:
復(fù)制代碼 代碼如下:
function getBaseName(str) {
var pos = str.lastIndexOf('.');
if(pos < 0)return str;
return str.substring(0, pos);
}
function getExtension(str) {
var pos = str.lastIndexOf('.');
if(pos < 0)return '';
return str.substr(pos+1);
}
var fileName = 'hello_world.js';
document.write(getBaseName(fileName));
document.write('<br />');
document.write(getExtension(fileName));
//output:
//hello_world
//js
(除了substr和substring外,JavaScript還有slice都可以用來(lái)獲取字符串的子串,但也正是因?yàn)檫x擇太多,常常讓我在出現(xiàn)選擇恐慌,還有位置是該不該+1,對(duì)負(fù)數(shù)是如何處理也讓我揪心。)
之前看到可以通過(guò)join把數(shù)組變成字符串,也可以利用String的split的方法把字符串變成數(shù)組。對(duì)于上邊取文件名及擴(kuò)展名的問(wèn)題,我們就可以根據(jù)“.”把文件名分裂成數(shù)組各個(gè)部分,那么假如得到的數(shù)字大于1(后綴名存在),則所得數(shù)字的最后一個(gè)元素就是文件的擴(kuò)展名了:
復(fù)制代碼 代碼如下:
function getBaseName(str) {
var segs = str.split('.');
if(segs.length > 1) segs.pop();
return segs.join('.');
}
function getExtension(str) {
var segs = str.split('.');
if(segs.length <= 1)return '';
return segs.pop();
}
考慮到文件名中可能包含多個(gè)“.”,所以我們還是需要用“.”把除了最后一部分外的各個(gè)部分join回來(lái)。
看到可以對(duì)字符串先split再join,就可以想到,我們可以想到對(duì)于這兩個(gè)方法的參數(shù)可以傳入不同的字符串,這樣就起到了代替String的replace方法進(jìn)行子串替換的功能了,而且還是全局替換。
比如希望把所有的下劃線(_)替換成橫杠(-):
復(fù)制代碼 代碼如下:
var str = 'hello_from_ider_to_world'.split('_').join('-');
document.write(str);
//Output:
// hello-from-ider-to-world
相對(duì)于String的replace方法,該方法的有點(diǎn)在于:可以實(shí)現(xiàn)全局替換;而若要讓replace能夠全局替換,則需要傳入正則表達(dá)式對(duì)象(RegExp)而不能是字符串作為第一參數(shù)。
replace可接受RegExp、Function作為參數(shù)
很多人知道String的replace方法是用來(lái)替換字符串子串的,也可能知道它可以接受正則表達(dá)式作為第一參數(shù),而且如何要替換所有出現(xiàn)的地方,就必須要用RegExp并包含global標(biāo)記。
比如之前的替換操作,用replace就應(yīng)該是:
復(fù)制代碼 代碼如下:
var str = 'hello_from_ider_to_world'.replace(/_/g, '-');
document.write(str);
再比如很常用的trim方法,雖然JavaScript并沒(méi)有提供我們也可以自己很快的實(shí)現(xiàn):
復(fù)制代碼 代碼如下:
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, '');
};
我們知道正則表達(dá)式一個(gè)很強(qiáng)大的功能就是向后引用(Back Reference),實(shí)際上JavaScript的replace不僅在第一個(gè)參數(shù)內(nèi)做向后引用,而且在替換字符串上,也可以進(jìn)行向后引用,只是很多地方可能用反斜杠(\)加數(shù)字作為標(biāo)示而JavaScript則是用美刀($)加數(shù)字作為標(biāo)示。
復(fù)制代碼 代碼如下:
var friends = 'friends of Ider, friend of Angie';
var result = friends.replace(/(friends?) of (\w+)/g, "$2's $1");
document.write(result);
//output:
//Ider's friends, Angie's friend
通過(guò)在替換字符串里面進(jìn)行向后引用,我們很快就把“朋友 of 誰(shuí)誰(shuí)誰(shuí)”變成了“誰(shuí)誰(shuí)誰(shuí)的朋友”。如果還要更復(fù)雜點(diǎn)怎么辦呢?沒(méi)有關(guān)系,replace還能接受Function作為參數(shù)作為回調(diào)函數(shù),其中函數(shù)的第一個(gè)參數(shù)是整個(gè)匹配中的字符串,之后每一個(gè)代表個(gè)個(gè)向后引用匹配的,函數(shù)的返回值則是作為替換的字符串。所以很多使用,函數(shù)參數(shù)都會(huì)用$0, $1, $2來(lái)表示。來(lái)看個(gè)例子:
復(fù)制代碼 代碼如下:
var friends ="friends of mine, friend of her and friends of his";
var result = friends.replace(/(friends?) of (\w+)/g,
function($0, $1, $2) {
if($2 == 'mine') $2 = 'my';
return $2 + ' ' + $1;
});
document.write(result);
//output:
//my friends, her friend and his friends
通過(guò)回調(diào)函數(shù)就可以實(shí)現(xiàn)很多很負(fù)責(zé)的字符串匹配了。至于效率,就先不考慮了。
您可能感興趣的文章:
- JS 對(duì)象(Object)和字符串(String)互轉(zhuǎn)方法
- JavaScript截取字符串的Slice、Substring、Substr函數(shù)詳解和比較
- js String對(duì)象中常用方法小結(jié)(字符串操作)
- js字符串的各種格式的轉(zhuǎn)換 ToString,F(xiàn)ormat
- js substring()字符串截取函數(shù)
- Javascript String 字符串操作包
- 幾個(gè)常用的JavaScript字符串處理函數(shù) - split()、join()、substring()和indexOf()
- Javascript類(lèi)型系統(tǒng)之String字符串類(lèi)型詳解
- javaScript字符串工具類(lèi)StringUtils詳解
- JavaScript的String字符串對(duì)象常用操作總結(jié)
- js字符串類(lèi)型String常用操作實(shí)例總結(jié)
相關(guān)文章
echarts實(shí)現(xiàn)餅圖與樣式設(shè)置
這篇文章介紹了echarts實(shí)現(xiàn)餅圖與樣式設(shè)置的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06js如何查找json數(shù)據(jù)中的最大值和最小值方法
這篇文章主要介紹了js如何查找json數(shù)據(jù)中的最大值和最小值方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04上傳文件返回的json數(shù)據(jù)會(huì)被提示下載問(wèn)題解決方案
這篇文章主要介紹了項(xiàng)目中python+js實(shí)現(xiàn)的上傳文件返回的json數(shù)據(jù)會(huì)被提示下載問(wèn)題解決方案,需要的朋友可以參考下2014-12-12JavaScript原生編寫(xiě)《飛機(jī)大戰(zhàn)坦克》游戲完整實(shí)例
飛機(jī)大戰(zhàn)坦克是一款小游戲,相信很多朋友都有玩過(guò),由于最近在深入學(xué)習(xí)Javascript,所以想著用利用Javascript來(lái)實(shí)現(xiàn)這個(gè)游戲,下面這篇文章主要介紹了如何利用JavaScript原生編寫(xiě)《飛機(jī)大戰(zhàn)坦克》游戲,需要的朋友可以參考下2017-01-01一個(gè)可以隨意添加多個(gè)序列的tag函數(shù)
由于在沒(méi)有規(guī)劃好的情況下寫(xiě)的這個(gè)代碼,寫(xiě)的比較粗糙,也沒(méi)有添加注釋。 JavaScript代碼和HTML完全分離;可以隨意添加多個(gè)子div標(biāo)簽,自動(dòng)擴(kuò)展2009-07-07