2.2 字符串
字符串经常被当成字符数组。字符串的内部实现究竟有没有使用数组并不好说,但 JavaScript 中的字符串和字符数组并不是一回事,最多只是看上去相似而已。
例如下面两个值:
var a = "foo"; var b = ["f","o","o"];
字符串和数组的确很相似,它们都是类数组,都有 length 属性以及 indexOf(..) (从 ES5 开始数组支持此方法)和 concat(..) 方法:
[source,js] a.length; // 3 b.length; // 3 a.indexOf( "o" ); // 1 b.indexOf( "o" ); // 1 var c = a.concat( "bar" ); // "foobar" var d = b.concat( ["b","a","r"] ); // ["f","o","o","b","a","r"] a === c; // false b === d; // false a; // "foo" b; // ["f","o","o"]
但这并不意味着它们都是“字符数组”,比如:
a[1] = "O"; b[1] = "O"; a; // "foo" b; // ["f","O","o"]
JavaScript 中字符串是不可变的,而数组是可变的。并且 a[1] 在 JavaScript 中并非总是合法语法,在老版本的 IE 中就不被允许(现在可以了)。正确 的方法应该是 a.charAt(1) 。
字符串不可变是指字符串的成员函数不会改变其原始值,而是创建并返回一个新的字符串。而数组的成员函数都是在其原始值上进行操作。
c = a.toUpperCase(); a === c; // false a; // "foo" c; // "FOO" b.push( "!" ); b; // ["f","O","o","!"]
许多数组函数用来处理字符串很方便。虽然字符串没有这些函数,但可以通过“借用”数组的非变更方法来处理字符串:
a.join; // undefined a.map; // undefined var 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."
另一个不同点在于字符串反转(JavaScript 面试常见问题)。数组有一个字符串没有的可变更成员函数 reverse() :
a.reverse; // undefined b.reverse(); // ["!","o","O","f"] b; // ["f","O","o","!"]
可惜我们无法“借用”数组的可变更成员函数,因为字符串是不可变的:
Array.prototype.reverse.call( a ); // 返回值仍然是字符串"foo"的一个封装对象(参见第3章):(
一个变通(破解)的办法是先将字符串转换为数组,待处理完后再将结果转换回字符串:
var c = a // 将a的值转换为字符数组 .split( "" ) // 将数组中的字符进行倒转 .reverse() // 将数组中的字符拼接回字符串 .join( "" ); c; // "oof"
这种方法的确简单粗暴,但对简单的字符串却完全适用。
请注意!上述方法对于包含复杂字符(Unicode,如星号、多字节字符等)的字符串并不适用。这时则需要功能更加完备、能够处理 Unicode 的工具库。可以参考 Mathias Bynen 的 Esrever(https://github.com/mathiasbynents/esrever )。
如果需要经常以字符数组 的方式来处理字符串的话,倒不如直接使用数组。这样就不用在字符串和数组之间来回折腾。可以在需要时使用 join("") 将字符数组 转换为字符串。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论