字符串(String)是不可变的、有限数量的字符序列,字符包括可见字符、不可见字符和转义字符。在程序设计中,经常需要处理字符串,如复制、替换、连接、比较、查找、截取、分割等。在JavaScript中,字符串是一类简单值,直接调用String原型方法就可以操作字符串。操作字符串在表单验证、HTML文本解析、Ajax异步交互等方面应用广泛。
1、字符串处理基础
1.1、定义字符串
1.字符串直接量
使用双引号或单引号包含任意长度的文本,可以定义字符串直接量。
【示例1】任何被引号包含的文本都称为字符串。
var s = "true"; //把布尔值转换为字符串
var s = "123"; //把数值转换为字符串
var s = "[1,2,3]"; //把数组转换为字符串
var s = "{x:1,y:2}"; //把对象转换为字符串
var s = "console.log('Hello,World')"; //把可执行表达式转换为字符串
【示例2】单引号和双引号可以配合使用,定义特殊形式的字符串。
var s = 'console.log("Hello,World")';
单引号可以包含双引号,或者双引号包含单引号。但是,不能在单引号中包含单引号,或者在双引号中包含双引号。
【示例3】表示特殊字符,需要使用转义字符。在下面字符串中,使用“\"”
表示双引号,这样可以直接用于双引号定义的字符串中。
var s = "\""; //有效的引号字符
2.构造字符串
使用String()类型函数可以构造字符串,该函数可以接收一个参数,并把它作为值初始化字符串。
【示例4】使用new运算符调用String()构造函数,将创建一个字符串型对象。
var s = new String(); //创建一个空字符串
var s = new String("我是构造字符串"); //创建字符串对象,初始化之后赋值给变量s
注意:通过String()构造函数构造的字符串与字符串直接量的类型是不同的。前者为引用型对象,后者为值类型的字符串。
【示例5】String()也可以直接使用,把参数转换为字符串类型的简单值返回。
var s = String( 123456 ); //包装字符串
console.log( s ); //返回字符串"123456"
【示例6】String()允许传入多个参数,但是仅处理第一个参数,并把它转换为字符串返回。
var s = String( 1, 2, 3, 4, 5, 6 ); //带有多个参数
console.log( s ); //返回字符串"1"
3.使用字符编码
使用fromCharCode方法可以把字符编码转换为字符串。该方法可以包含多个参数,每个参数代表字符的Unicode编码,返回字符串表示。
【示例7】演示把一组字符串编码转换为字符串。
var a = [35835, 32773, 24744, 22909], b = []; //声明一个字符编码的数组
for( var i in a ){ //遍历数组
b.push( String.fromCharCode( a[i] ) ); //把每个字符编码都转换为字符串存入数组
}
console.log( b.join( "" ) ); //返回字符串"读者您好"
也可以把所有字符串按顺序传给fromCharCode():
var b = String.fromCharCode( 35835, 32773, 24744, 22909 ) ; //传递多个参数
提示:fromCharCode()是String类型的静态函数,不能通过字符串调用。与fromCharCode()相反,charCodeAt()可以把字符转换为Unicode编码。
1.2、获取长度
使用字符串的length属性可以读取字符串的长度。长度以字符为单位,该属性为只读属性。
【示例1】使用字符串的length属性获取字符串的长度:
var s = "String类型长度"; //定义字符串
console.log(s.length); //返回10个字符
注意:JavaScript支持的字符包括单字节、双字节两种类型。为了精确计算字符串的字节长度,可以采用示例2的方法来计算。
【示例2】为String扩展原型方法byteLength(),该方法将枚举每个字符,并根据字符编码,判断当前字符是单字节还是双字节,然后统计字符串的字节长度。
应用原型方法:
var s = "String类型长度"; //定义字符串直接量
console.log(s.byteLength()) //返回14
1.3、连接字符串
1.使用加号运算符
连接字符串的最简便方法是使用加号运算符。
【示例1】使用加号运算符连接两个字符串:
var s1 = "abc", s2 = "def";
console.log(s1+s2); //返回字符串"abcdef"
2.使用concat()
使用字符串的concat()方法可以把多个参数添加到指定字符串的尾部。该方法的参数类型和个数没有限制,它会把所有参数都转换为字符串,然后按顺序连接到当前字符串的尾部,最后返回连接后的新字符串。
【示例2】使用字符串的concat()方法把多个字符串连接在一起:
var s1 = "abc";
var s2 = s1.concat( "d", "e", "f" ); //调用concat()连接字符串
console.log( s2 ); //返回字符串"abcdef"
提示:concat()方法不会修改原字符串的值,与数组的concat()方法操作相似。
3.使用join()
在特定环境中,可以借助数组的join()方法连接字符串,如HTML字符串输出等。
【示例3】演示借助数组的方法连接字符串:
var s = "JavaScript", a = []; //定义一个字符串
for(var i = 0; i < 1000; i ++ ) //循环执行1000次
a.push(s); //把字符串装入数组
var str = a.join(""); //通过join()方法把数组元素连接在一起
a = null; //清空数组
document.write(str);
在上面示例中,使用for语句把1000个“JavaScript”字符串装入数组,然后调用数组的join()方法把元素的值连接成一个长长的字符串。使用完毕应该立即清除数组,避免占用系统资源。
1.4、检索字符串
检索字符串的方法有多种,简单说明如下表所示:
1.查找字符
使用字符串的charAt()和charCodeAt()方法,可以根据参数(非负整数的下标值)返回指定位置的字符或字符编码。
提示:对于charAt()方法来说,如果参数不在0~length-1,则返回空字符串。而对于charCodeAt()方法来说,则返回NaN,而不是0或空字符串。
【示例1】为String类型扩展一个原型方法,用来把字符串转换为数组。在函数中使用charAt()方法读取字符串中每个字符,然后装入一个数组并返回:
String.prototype.toArray = function(){ //把字符串转换为数组
var l = this.length, a = []; //获取当前字符串长度,并定义空数组
if( l ){ //如果存在则执行循环操作,预防空字符串
for( var i = 0; i < l; i ++ ){ //遍历字符串,枚举每个字符
a.push( this.charAt( i ) ); //把每个字符按顺序装入数组
}
}
return a; //返回数组
}
应用原型方法:
var s = "abcdefghijklmn".toArray(); //把字符串转换为数组
for(var i in s){ //遍历返回数组,显示每个字符
console.log(s[i]);
}
2.查找字符串
使用字符串的indexOf()和lastIndexOf()方法,可以根据参数字符串,返回指定子字符串的下标位置。这两个方法都有两个参数。
- 第一个参数为一个子字符串,指定要查找的子串。
- 第二个参数为一个整数,指定开始查找的起始位置,取值范围是0~length-1。
对于第二个参数来说,有几种特殊情况需要注意:
- 如果值为负数,则视为0,相当于从第一个字符开始查找。
- 如果省略这个参数,也将从字符串的第一个字符开始查找。
- 如果值大于等于length属性值,则视为当前字符串中没有指定的子字符串,返回-1。
【示例2】查询字符串中首个字母a的下标位置:
var s = "JavaScript";
var i = s.indexOf("a");
console.log(i); //返回值为1,即字符串中第二个字符
indexOf()方法只返回查找到的第一个子字符串的起始下标值,如果没有找到则返回-1。
3.搜索字符串
search()方法与indexOf()功能相同,都是查找指定字符串第一次出现的位置。但是search()方法仅有一个参数,定义匹配模式。该方法没有lastIndexOf()的反向检索功能,也不支持全局模式。
【示例】使用search()方法匹配斜杠字符在URL字符串的下标位置:
var s = "http://www.mysite.cn/index.html";
var n = s.search( "//" ); //返回值为5
注意:使用search()方法时,需要注意以下几点:
- search()方法的参数为正则表达式(RegExp对象)。如果参数不是RegExp对象,则JavaScript会使用RegExp()函数把它转换成RegExp对象。
- search()方法遵循从左到右的查找顺序,并返回第一个匹配的子字符串的起始下标位置值。如果没有找到,则返回-1。
- search()方法无法查找指定的范围,始终返回的第一个匹配子字符串的下标值,没有indexOf()方法灵活。
4.匹配字符串
match()方法能够找出所有匹配的子字符串,并以数组的形式返回。
【示例】使用match()方法找到字符串中所有字母h,并返回它们:
var s = "http://www.mysite.cn/index.html";
var a = s.match( /h/g ); //全局匹配所有字符h
console.log( a ); //返回数组[h,h]
match()方法返回的是一个数组,如果不是全局匹配,match()方法只能执行一次匹配。例如,匹配模式没有g修饰符,只能执行一次匹配,返回仅有一个元素h的数组:
var a = s.match( /h/ ); //返回数组[h]
如果没有找到匹配字符,则返回null,而不是空数组。
当不执行全局匹配时,如果匹配模式包含子表达式,则返回子表达式匹配的信息。
1.5、截取字符串
截取字符串的方法有3种,简单说明如下表所示:
1.截取指定长度字符串
substr()方法能够根据指定长度截取子字符串。它包含两个参数:第一个参数表示准备截取的子串的起始下标;第二个参数表示截取的长度。
【示例1】使用lastIndexOf()获取字符串的最后一个点号的下标位置,然后从其后的位置开始截取4个字符:
var s = "http://www.mysite.cn/index.html";
var b = s.substr( s.lastIndexOf( "." )+1, 4 ); //截取最后一个点号后4个字符
console.log( b ); //返回子字符串"html"
注意:如果省略第二个参数,则表示截取从起始位置开始到结尾的所有字符。考虑到扩展名的长度不固定,省略第二个参数会更灵活。
var b = s.substr( s.lastIndexOf( "." )+1 );
如果第一个参数为负值,则表示从字符串的尾部开始计算下标位置,即-1表示最后一个字符,-2表示倒数第二个字符,以此类推。这对于左侧字符长度不固定时非常有用。
提示,ECMAScript不再建议使用该方法,推荐使用slice()和substring()方法。
2.截取起止下标位置字符串
slice()和substring()方法都是根据指定的起止下标位置截取子字符串。它们都可以包含两个参数:第一个参数表示起始下标;第二个参数表示结束下标。
【示例2】使用substring()方法截取URL字符串中网站主机名信息:
var s = "http://www.mysite.cn/index.html";
var a = s.indexOf( "www" ); //获取起始点的下标位置
var b = s.indexOf( "/", a ); //获取结束点后面的下标位置
var c = s.substring( a, b ); //返回字符串www.mysite.cn
var d = s.slice( a, b ); //返回字符串www.mysite.cn
注意:关于slice()和substring()方法的参数,需要注意如下两点:
- 截取的字符串包含第一个参数所指定的字符。结束点不被截取。
- 第二个参数如果省略,表示截取到结尾的所有字符串。
提示:slice()方法和substring()方法使用比较。
如果第一个参数值比第二个参数值大,substring()方法能够在执行截取之前,先交换两个参数,而对于slice()方法则被视为无效,并返回空字符串。
1.6、替换字符串
使用字符串的replace()方法可以替换指定的子字符串。该方法包含两个参数:第一个参数表示执行匹配的正则表达式;第二个参数表示准备替换匹配的子串。
【示例1】使用replace()方法替换字符串中的html为htm:
var s = "http://www.mysite.cn/index.html";
var b = s.replace( /html/, "htm" ); //把字符串html替换为htm
console.log( b ); //返回字符串“http://www.mysite.cn/index.htm”
1.7、转换大小写
转换字符串大小写有4种方法,简单说明如下表所示:
【示例】把字符串全部转换为大写形式:
var s = "JavaScript";
console.log(s.toUpperCase()); //返回字符串“JAVASCRIPT”
提示:toLocaleLowerCase()和toLocaleUpperCase()是两个本地化方法。它们能够按照本地方式转换大小写字母,由于只有几种语言(如土耳其语)具有地方特有的大小写映射,所以通常与toLowerCase()和toUpperCase()方法的返回值一样。
1.8、转换为数组
使用split()方法可以根据指定的分隔符把字符串转切分为数组。相反,如果使用数组的join()方法,可以把数组元素连接为字符串。
【示例1】如果参数为空字符串,则split()方法能够按单个字符进行分切,然后返回与字符串等长的数组:
var s = "JavaScript";
var a = s.split(""); //按字符空隙分割
console.log( s.length ); //返回值为10
console.log( a.length ); //返回值为10
提示:关于split()方法,需要注意以下几点:
- 如果参数为空,则split()方法能够把整个字符串作为一个元素的数组返回。
- 如果参数为正则表达式,则split()方法以匹配的文本作为分隔符进行切分。
- 如果正则表达式匹配的文本位于字符串的边沿,则split()方法执行分切操作,且为数组添加一个空元素。
- 如果在字符串中指定的分隔符没有找到,则返回一个包含整个字符串的数组。
split()方法支持第二个参数,该参数是一个可选的整数,用来指定返回数组的最大长度。如果设置该参数,返回的数组长度不会多于这个参数指定的值。如果没有设置该参数,将分割整个字符串,不考虑数组长度。例如:
var s = "JavaScript";
var a = s.split("",4); //按顺序从左到右,仅分切4个元素的数组
console.log( a ); //返回数组[J,a,v ,a]
console.log( a.length ); //返回值为4
【示例2】如果想使返回的数组包括分隔符或分隔符的一个或多个部分,可以使用带子表达式的正则表达式实现:
var s = "aa2bb3cc4dd5e678f12g";
var a = s.split(/(\d)/); //使用小括号包含数字分隔符
console.log(a); //返回数组[aa,2,bb,3,cc,4,dd,5,e,6,,7,,8,f,1,,2,g]
1.9、清除字符串
使用trim()方法可以从字符串中移除前导空字符、尾随空字符和行终止符。该方法在表单处理中非常实用。
提示:空字符包括空格、制表符、换页符、回车符和换行符。
【示例】使用trim()方法快速清除字符串首尾空格:
var s = " abc def \r\n ";
s = s.trim();
console.log("[" + s + "]"); //[abc def]
console.log(s.length); //7
1.10、Unicode编码和解码
JavaScript定义了6个全局方法,用于Unicode字符串的编码和解码,说明如下表所示:
1.escape()和unescape()方法
escape()方法能够把除ASCII之外的所有字符转换为%xx或%uxxxx(x表示十六进制的数字)的转义序列。从\u0000到\u00ff的Unicode字符由转义序列%xx替代,其他所有Unicode字符由%uxxxx序列替代。
【示例1】使用escape()方法编码字符串:
var s = "JavaScript中国";
s = escape(s);
console.log(s); //返回字符串“JavaScript%u4E2D%u56FD”
可以使用该方法对Cookie字符串进行编码,避免与其他约定字符发生冲突,因为Cookie包含的标点符号是有限制的。
与escape()方法对应,unescape()方法能够对escape()编码的字符串进行解码。
【示例2】使用unescape()方法解码被escape()方法编码的字符串:
var s = "JavaScript中国";
s = escape(s); //Unicode编码
console.log(s); //返回字符串“JavaScript%u4E2D%u56FD”
s = unescape(s); //Unicode解码
console.log(s); //返回字符串“JavaScript中国”
2.encodeURI()和decodeURI()方法
encodeURI()方法能够把URI字符串进行转义处理。例如:
var s = "JavaScript中国";
s = encodeURI(s);
console.log(s); //返回字符串“JavaScript%E4%B8%AD%E5%9B%BD”
encodeURI()方法与escape()方法的编码结果是不同的,但是它们都不会编码ASCII字符。
相对而言,encodeURI()方法更加安全。它能够将字符转换为UTF-8编码字符,然后用十六进制的转义序列(形式为%xx)对生成的1个、2个或4个字节的字符编码。
使用decodeURI()方法可以对encodeURI()方法的结果进行解码。
【示例3】演示对URL字符串进行编码和解码操作:
var s = "JavaScript中国";
s = encodeURI(s); //URI编码
console.log(s); //返回字符串“JavaScript%E4%B8%AD%E5%9B%BD”
s = decodeURI(s); //URI解码
console.log(s); //返回字符串“JavaScript中国”
3.encodeURIComponent()和decodeURIComponent()方法
encodeURIComponent()与encodeURI()方法不同。它们的主要区别就在于,encodeURIComponent()方法假定参数是URI的一部分,例如,协议、主机名、路径或查询字符串,因此它将转义用于分隔URI各个部分的标点符号;而encodeURI()方法仅把它们视为普通的ASCII字符,并没有转换。
【示例4】URL字符串被encodeURIComponent()方法编码前后的比较:
var s = "http://www.mysite.cn/navi/search.asp?keyword=URI";
a = encodeURI(s);
console.log( a);
b = encodeURIComponent(s);
console.log(b);
输出显示为:
http://www.mysite.cn/navi/search.asp?keyword=URI
http%3A%2F%2Fwww.mysite.cn%2Fnavi%2Fsearch.asp%3Fkeyword%3DURI
第一行字符串是encodeURI()方法编码的结果,第二行字符串是encodeURIComponent()方法编码的结果。与encodeURI()方法一样,encodeURIComponent()方法对于ASCII字符不编码,而用于分隔URI各种组件的标点符号,都由一个或多个十六进制的转义序列替换。
使用decodeURIComponent()方法可以对encodeURIComponent()方法编码的结果进行解码:
var s = "http://www.mysite.cn/navi/search.asp?keyword=URI";
b = encodeURIComponent(s);
b = decodeURIComponent(b)
console.log(b);
1.11、Base64编码和解码
Base64是一种编码方法,可以将任意字符(包括二进制字节流)转换成可打印字符。JavaScript定义了两个与Base64相关的全局方法:
- btoa():字符串或二进制字节串转为Base64编码。
- atob():把Base64编码转为原来字符。
注意:Base64方法不能够操作非ASCII字符。
【示例】要将非ASCII码字符转为Base64编码,必须先把Unicode双字节字符串转换为ASCII字符表示,再使用这两个方法:
function b64Encode(str) {
return btoa(encodeURIComponent(str));
}
function b64Decode(str) {
return decodeURIComponent(atob(str));
}
var b = b64Encode('JavaScript从入门到精通');
var a = b64Decode(b);
console.log(b); //返回 SmF2YVNjcmlwdCVFNCVCQiU4RSVFNSU4NSVBNSVFOSU5NyVB
OCVFNSU4OCVCMCVFNyVCMiVCRSVFOSU4MCU5QQ= =
console.log(a); //返回'JavaScript从入门到精通'
1.12、字符串模板
ECMAScript 6允许使用反引号(`)创建字符串,使用这种方法创建的字符串可以包含由美元符号加大括号包裹的变量${vraible}。例如:
let num = Math.random(); //产生一个随机数
console.log(`your num is ${num}`); //使用字符串模板将这个数字输出到控制台