keywords:string,indexOf,concat,split,reverse,join

字串( String )

普遍的看法是『 string 基本上只是字元所組成的 array 』,但實際上並不等於,string 與 array 相似的只有表面而已。
相似的地方:

  1. 它們都是 array-like
  2. 都有 length 特性
  3. indexOf(..) 方法 ( ES5 只有 array 版本的 )
  4. concat(..) 方法
    • Array.prototype.concat() 被用來合併兩個或多個陣列。 此方法不會改變原本的陣列,回傳一個包含呼叫者陣列本身的值,作為代替的是回傳一個新陣列。
    • String.prototype.concat() 被用來聯集一個以上的字串,原字串不會被改變並回傳一個新的字串。

看看例子:

    let a = 'egg';

    let b = ['e','g','g'];


    a.length; // 3

    b.length; // 3


    a.indexOf('g'); // 1

    b.indexOf('g'); // 1


    let c = a.concat('cake'); // 'eggcake'

    let d = b.concat(['c','a','k','e']); // ['e','g','g','c','a','k','e']


    a === c; // false

    b === d; // false


    a; // 'egg'

    b; // ['e','g','g']

不相似的地方:

  1. string 是不可變的 ( immutable )
  2. array 是可變的( mutable )

看看例子:

    a[1] = 'G';

    b[1] = 'G';


    a; // egg

    b; // ['e','G','g']

a[1] 這種字元位置的存取動作,並非總是有效 舊版 IE 就不允許這種語法 ( 雖然現在可以了 ),但比較正確的做法是 a.charAt(1)

不可變的 string V.S. 可變的 array

  • 不可變的 string:所有會更動內容的 string 方法都無法就地( in-place )修改,必須建立並回傳一個新的 string

      let a = 'egg';
    
      let c = a.toUpperCase();
    
      a === c; // false
    
      a; 'egg'
    
      c; 'EGG'
    
  • 可變的 array:許多會變更陣列內容的陣列方法實際上都是就地進行修改動作

      let b = ['e','g','g'];
    
      b.push('!');
    
      b; // ['e','g','g','!']
    

處理不可變的 string 時想要使用不會變動內容的 array 方法

雖然 array 方法無法直接被 string 取用,不過可以借取 ( borrow ) 🚩注意只有不會變動內容的 array 方法可借取
看看例子:

    let a = 'egg';


    a.join('-'); // TypeError: a.join is not a function

    a.map(item => item.toUpperCase()); // TypeError: a.map is not a function


    Array.prototype.join.call(a,'-'); // 'e-g-g'

    時常搞不清楚 .call 到底是怎麼一回事,所以都會把上面這行想像成是這樣 ( 僅方便理解 ): a.join('-'); 


    Array.prototype.map.call(a,item => item.toUpperCase() + '.').join(''); // 'E.G.G'

    僅方便理解的樣子: a.map(item => item.toUpperCase());

處理不可變的 string 時想要使用會變動內容的 array 方法

  • Array.prototype.reverse() 就地 ( in place ) 的反轉 array,即第一個元素變成最後一個,而最後一個元素變成第一個。

看看例子:

    let a = 'egg';

    let b = ['e','g','g'];


    a.reverse(); // TypeError: a.reverse is not a function

    b.reverse(); // ['g', 'g', 'e']


    Array.prototype.reverse.call(a);

    // TypeError: Cannot assign to read only property '0' of object '[object String]'

因為 reverse 是 array 就地修改內容的方法,那如果想要反轉字串怎做呢? 🤔
先把字串轉成 array 就可以用 reverse 方法了,然後再轉回 string 😏

    a.split('').reverse().join('');  // gge

等等 太快了! split()? join()?

  • String.prototype.split() 將字串依照第一個參數( 分離器 )劃分為有序列的子串字集放入 array,並回傳該 array。

      const str = 'Egg is good';
    
      str.split(); // ['Egg is good']
    
      str.split(''); // ['E', 'g', 'g', ' ', 'i', 's', ' ', 'g', 'o', 'o', 'd']
    
      str.split(' '); //  ['Egg', 'is', 'good']
    
      str; // 'Egg is good'
    
  • Array.prototype.join() 將 array or array-like object 依照 , 或是傳入的分隔符號聯集建立並回傳一個新 string,如果 array 只有一個項目將回傳該值,並不會有任何的分隔符號。

      const el = ['egg', 'water', 'fruit'];
    
      el.join(); // egg,water,fruit
    
      el.join('-'); // egg-water-fruit
    
      ['egg'].join(); // egg
    

    回到上方的 string 想達到使用 array.reverse 一樣效果的例子:

       a.split('').reverse().join('');  // gge
    
       step1:
       a.split(''); // ['e','g','g']
    
       step2:
       a.reverse(); // ['g', 'g', 'e']
    
       step3:
       a.join(''); // gge
    

    要小心這種作法不適用於含有複雜 ( unicode ) 字元、astral符號、多位元組字元等的 string

Tip:如果字串較常把它當作字元所成陣列來對待,比較好的方法是實際上儲存為 array,而非 string,如果需要用到 string 的時候再呼叫 join(..) 轉成 string 即可。

#string #indexOf #concat #split #Reverse #join







Related Posts

【Day05】實戰開始 - 區塊分割

【Day05】實戰開始 - 區塊分割

Todo list_Part2:UI 拿出資料與串接後端

Todo list_Part2:UI 拿出資料與串接後端

七天打造自己的 Google Map 應用入門 - Day03

七天打造自己的 Google Map 應用入門 - Day03




Sponsored



Comments