字符串经常被当成字符数组。 字符串的内部实现究竟有没有使用数组并不好说,但JavaScript中的字符串和字符数组并不是一回事,最多只是看上去相似而已。
例如:
var a = 'foo'var b = ['f', 'o', 'o']
字符串和数组的确很相似,它们都是类数组都有length属性以及indexOf(…)(从ES5开始数组支持此方法)和concat(…)方法。
a.length // 3b.length // 3a.indexOf('o') // 1b.indexOf('o') // 1var c = a.concat('bar) // 'foobar'var d = b.concat(['b', 'a', 'r']) // ['f', 'o', 'o', 'b', 'a', 'r']a === c // falseb === d // falsea // 'foo'b // ['f', 'o', 'o']
但是并不意味着它们都是“字符数组”,比如:
a[1] = '1'b[1] = '1'a // 'foo'b // ['f', '1', 'o']
JavaScript中字符串是不可变的,而数组是可变的。并且a[1]在JavaScript中并非总是合法语法,在老版本的IE中就不被允许(现在可以了),正确的方法是a.charAt(1)。
字符串不可变是指字符串的成员函数不会改变其原始值,而是创建并返回一个新的字符串。而数组的成员函数都是在其原始值上进行操作。
c = a.toUpperCase();a === c; // falsea; // "foo"c; // "FOO"b.push( "!" );b; // ["f","O","o","!"]
许多数组函数用来处理字符串很方便,虽然字符串没有这些函数,但可以通过“借用”数组的非变更方法来处理字符串。
a.join; // undefineda.map; // undefinedvar c = Array.prototype.join.call( a, "-" );var d = Array.prototype.map.call( a, function(v){return v.toUpperCase() + ".";} ).join( "" );c; // "f-o-o"d; // "F.O.O."
另一个不同点在于字符串反转(面试常见问题),数组有一个字符串没有的可变更成员函数reverse()。
a.reverse; // undefinedb.reverse(); // ["!","o","O","f"]b; // ["!","o","O","f"]
可惜我们无法”借用”字符串的可变更成员函数,因为字符串是不可变的。
Array.prototype.reverse.call( a );// 返回值仍然是字符串"foo"的一个封装对象(参考第三章)
一个变通方法是先将字符串转为数组,待处理完成后,再将结果转回字符串。
var c = a// 将a的值转换为字符数组.split( "" )// 将数组中的字符进行倒转.reverse()// 将数组中的字符拼接回字符串.join( "" );c; // "oof"
注意:上述方法对于包含复杂字符(Unicode,如星号、多字节字符等)的字符串并不适用。这时则需要功能更加完备,能够处理Unicode的工具库。
如果需要经常以字符数组的方式来处理字符串的话,倒不如直接使用数组,然后在需要时使用 join('') 将字符数组转换为字符串。
