字符串经常被当成字符数组。 字符串的内部实现究竟有没有使用数组并不好说,但JavaScript中的字符串和字符数组并不是一回事,最多只是看上去相似而已。
    例如:

    1. var a = 'foo'
    2. var b = ['f', 'o', 'o']

    字符串和数组的确很相似,它们都是类数组都有length属性以及indexOf(…)(从ES5开始数组支持此方法)和concat(…)方法。

    1. a.length // 3
    2. b.length // 3
    3. a.indexOf('o') // 1
    4. b.indexOf('o') // 1
    5. var c = a.concat('bar) // 'foobar'
    6. var d = b.concat(['b', 'a', 'r']) // ['f', 'o', 'o', 'b', 'a', 'r']
    7. a === c // false
    8. b === d // false
    9. a // 'foo'
    10. b // ['f', 'o', 'o']

    但是并不意味着它们都是“字符数组”,比如:

    1. a[1] = '1'
    2. b[1] = '1'
    3. a // 'foo'
    4. b // ['f', '1', 'o']

    JavaScript中字符串是不可变的,而数组是可变的。并且a[1]在JavaScript中并非总是合法语法,在老版本的IE中就不被允许(现在可以了),正确的方法是a.charAt(1)。
    字符串不可变是指字符串的成员函数不会改变其原始值,而是创建并返回一个新的字符串。而数组的成员函数都是在其原始值上进行操作。

    1. c = a.toUpperCase();
    2. a === c; // false
    3. a; // "foo"
    4. c; // "FOO"
    5. b.push( "!" );
    6. b; // ["f","O","o","!"]

    许多数组函数用来处理字符串很方便,虽然字符串没有这些函数,但可以通过“借用”数组的非变更方法来处理字符串。

    1. a.join; // undefined
    2. a.map; // undefined
    3. var c = Array.prototype.join.call( a, "-" );
    4. var d = Array.prototype.map.call( a, function(v){
    5. return v.toUpperCase() + ".";
    6. } ).join( "" );
    7. c; // "f-o-o"
    8. d; // "F.O.O."

    另一个不同点在于字符串反转(面试常见问题),数组有一个字符串没有的可变更成员函数reverse()。

    1. a.reverse; // undefined
    2. b.reverse(); // ["!","o","O","f"]
    3. b; // ["!","o","O","f"]

    可惜我们无法”借用”字符串的可变更成员函数,因为字符串是不可变的。

    1. Array.prototype.reverse.call( a );
    2. // 返回值仍然是字符串"foo"的一个封装对象(参考第三章)

    一个变通方法是先将字符串转为数组,待处理完成后,再将结果转回字符串。

    1. var c = a
    2. // 将a的值转换为字符数组
    3. .split( "" )
    4. // 将数组中的字符进行倒转
    5. .reverse()
    6. // 将数组中的字符拼接回字符串
    7. .join( "" );
    8. c; // "oof"

    注意:上述方法对于包含复杂字符(Unicode,如星号、多字节字符等)的字符串并不适用。这时则需要功能更加完备,能够处理Unicode的工具库。
    如果需要经常以字符数组的方式来处理字符串的话,倒不如直接使用数组,然后在需要时使用 join('') 将字符数组转换为字符串。