--- tags: 如何正確使用字串, 字串 or 陣列處理方法, string, 陣列, array, indexOf, lastIndexOf, includes, 嚴格相等比較, SameValueZero, SameValueNonNumeric, searchElement, search --- 尋找是否包含某元素:includes、indexOf === :::spoiler 目錄 - includes、indexOf - indexOf - 參數 - 範例 - 搜索空字串 - 參數 position 是負值 - 文字 - 陣列 - 從後面往前找:lastIndexOf - 參數 - 範例 - 與 indexOf 的不同 - search - includes - 範例 - indexOf 與 includes 的差異 - 回傳值 - 關於 NaN 的問題 - 關於空陣列的問題 - 嚴格相等比較 vs. SameValueZero - 嚴格相等比較 - SameValueZero - 元素型別為 Object 時,需要考慮值的參考 ::: <br/> 返回新的值,++不會更改原始的值++。 includes、indexOf --- | | 過去 | ES7 | | -------- | -------- | -------- | | 尋找是否包含某元素 | ++indexOf++ | ++includes++ | | | ++lastIndexOf++ | | 尋找陣列中是否包含某元素,過去使用 indexOf 處理,現在 ES7 有 includes 可以使用。 假若比對的是字串,可以使用 match、search,詳細見:[尋找比對字串:match、search](https://hackmd.io/wk6ELp3pTSujIwf8yDlFjQ?view)。 indexOf --- 回傳元素於 **陣列 / 字串** 中第一個被找到之**索引**,若不存在於陣列 / 字串中則回傳 -1。 ### Ⅰ. 參數 > indexOf ( searchString [ , fromIndex] ) - searchElement:選填,判斷的值,預設為 `undefined`。 - fromIndex:選填,從哪個位置開始判斷,預設為 0。 :::spoiler 如果<u>未搜尋成功,返回 -1</u>。 ```jsx "0123".indexOf("A"); // -1 "0123".indexOf("1",99); // -1 [2, 9, 9].indexOf(7); // -1 [2, 9, 9].indexOf(2, 1); // -1 ``` ::: :::spoiler 參數 searchString <u>沒有指定,默認搜尋的是 `undefined`</u>。 ```jsx "0123".indexOf(); // -1 'undefined'.indexOf(); // 0 [2, 9, 9].indexOf(); // -1 [undefined].indexOf(); // 0 ``` ::: :::spoiler 參數 searchString 區分大小寫。 ```jsx let string = "Hello World!"; string.indexOf("h"); // -1 string.indexOf("H"); // 0 ``` ::: ### Ⅱ. 範例 ```jsx let string = "Hello World!"; string.indexOf("!"); // 11 string.indexOf("!",11); // 11 ``` ```jsx let array = [2, 9, 9]; array.indexOf(2); // 0 array.indexOf(9, 2); // 2 ``` > [Dome](https://codepen.io/betty-hu/pen/NWXeJeV) ### Ⅲ. 搜索空字串 搜索空字串,假若 fromIndex 參數小於字串長度,結果將是 fromIndex 的值。反之,將會是字串長度。 :::spoiler 沒有 fromIndex 參數的情況,返回 0。 ```jsx "0123".indexOf(""); // 0 ``` ::: :::spoiler 參數 fromIndex 小於字串長度,返回 fromIndex 的值。 ```jsx "0123".indexOf("",1); // 1 ``` ▲ ( fromIndex 參數 = 1 ) < (字串長度 = 4) → 返回 fromIndex 的值 = 1 ::: :::spoiler 參數 fromIndex 大於字串長度,返回字串長度。 ```jsx "0123".indexOf("",99); // 4 ``` ▲ ( fromIndex 參數 = 99 ) > (字串長度 = 4) → 返回字串長度 = 4 ::: :::spoiler 假若對象是陣列的話,返回 -1。 ```jsx [0,1,2,3].indexOf("",1); // -1 ``` ::: ### Ⅳ. 參數 fromIndex 是負值 #### Ⅳ-1. 文字 參數 fromIndex 是負值,假若是文字,將會視作為 0,也就是搜索全部。 ```jsx "Hello World!".indexOf("World",-1); // 6 ``` #### Ⅳ-2. 陣列 參數 fromIndex 是負值,假若是陣列,從後方往前計算。 最後一個的索引值是 -1,也就是說 fromIndex = -1,等於最後一項,以此類推。 ```jsx ["Hello", "World", "!"].indexOf("!",-1); // 2 ["Hello", "World", "!"].indexOf("World",-1); // -1 ["Hello", "World", "!"].indexOf("World",-2); // 1 ``` ### Ⅴ. 從後面往前找:lastIndexOf 與 indexOf 相同,但是從後面往前找。 #### Ⅰ.參數 > lastIndexOf ( searchElement [ , fromIndex ] ) - searchElement:選填,判斷的值,預設為 `undefined`。 - fromIndex:選填,從哪個位置開始判斷,預設為最後一項。 #### Ⅱ. 範例 ```jsx "Hello World!".lastIndexOf("!"); // 11 "Hello World!".lastIndexOf("!",10); // -1 ``` > [Dome](https://codepen.io/betty-hu/pen/bGQOMLV?editors=0012#_=_) #### Ⅲ. 與 indexOf 的不同 ```jsx "abcabc".lastIndexOf("a"); // 3 "abcabc".lastIndexOf("a",5); // 3 "abcabc".indexOf("a"); // 0 "abcabc".lastIndexOf("a",0); // 0 ``` ▲ fromIndex 預設最後一項。 ```jsx "abcabc".indexOf(""); // 0 "abcabc".lastIndexOf(""); // 6 ``` ▲ 搜索空字串:沒有 fromIndex 參數的情況,返回字串長度。 ```jsx "abcabc".indexOf("c",-3); // 2 (負數視作搜尋全部) "abcabc".lastIndexOf("c",-3); // -1 ``` ▲ 參數 fromIndex 是負值,假若是文字,將會回傳 -1。 ### Ⅵ. search > str . search ( regexp ) ```jsx /* 沒有使用正規表達式,僅使用字串搜尋 */ 'some text'.search('text') // 0 'some text'.search('TEXT') // -1 /* 使用正規表達式 */ 'some text'.search(/TEXT/i) // 0 ``` 找出字串在另一字串中的位置,有找到回傳字串的起始位置,沒找到回傳 -1。 跟 `indexOf()` 相同都是尋找並回傳位置,只是 `search()` 可以用正規表示式當參數,且只能作用在字串上,不能用於陣列。詳細見:[尋找比對字串:match、search](https://hackmd.io/wk6ELp3pTSujIwf8yDlFjQ?view) includes --- ES7 提供的新函式。直接回傳是否包含該元素的 Boolean 值,true 代表包含、false 代表不包含。 #### 參數 > includes ( searchElement [ , fromIndex] ) - searchElement:選填,判斷的值,預設為 undefined。 - fromIndex:選填,從哪個位置開始判斷,預設為 0。 用法同 indexOf。 #### Ⅰ. 範例 ```jsx 'JS ECMA TC39'.includes('ECMA'); // true ['JS', 'ECMA', 'TC39'].includes('ECMA'); // true ['JS ECMA TC39'].includes('ECMA'); // false /* searchElement 預設 */ "undefined".includes(); // true [undefined].includes(); // true /* fromIndex 參數 */ "abcdef".includes("c",3); // false "abcdef".includes("c",-3); // true ['JS', 'ECMA', 'TC39'].includes('ECMA', 1); // true ['JS', 'ECMA', 'TC39'].includes('ECMA', -1); // false /* 搜索空字串 */ "abcdef".includes(""); // true [00,11,22].includes(""); // false ``` > [Dome](https://codepen.io/betty-hu/pen/zYMeRRM?editors=0012) indexOf 與 includes 的差異 --- ### 回傳值 - indexOf:回傳元素於 陣列 / 字串 中第一個被找到之索引。 - includes:回傳是否包含該元素的 Boolean 值。 ```jsx ['JS', 'ECMA', 'TC39'].indexOf('ECMA'); // 1 ['JS', 'ECMA', 'TC39'].indexOf('ECMA') == true // true ['JS', 'ECMA', 'TC39'].indexOf('ECMA') !== -1 // true ['JS', 'ECMA', 'TC39'].includes('ECMA'); // true ``` ### 關於 NaN 的問題 - indexOf:使用嚴格相等比較,而 NaN !== NaN,無法在陣列中找到 NaN。 - includes:使用 searchElement 演算法,可以解決 NaN 的問題。 ```jsx [NaN].indexOf(NaN) !== -1 // false [NaN].includes(NaN) // true ``` ### 關於空陣列的問題 - indexOf:遇到空陣列會直接跳過,繼續比對下個元素,無法在陣列中找到空陣列。 - includes:不會跳過空陣列,而是視為 `undefined`,因此能夠捕抓空陣列。 ```jsx // Array(3) = [ , , ] Array(3).indexOf() !== -1 // false Array(3).includes() // true ``` 嚴格相等比較 vs. SameValueZero --- indexOf 採用嚴格相等比較;includes 採用 SameValueZero。 ### ++嚴格相等比較++ 1. 比較型別是否相同,不同就回傳 false。 2. 型別是 Number 或 BigInt ,**進行值的比較**。在值的比較中,++值是 NaN 回傳 false,這是 indexOf 中 NaN 不等於 NaN 的原因++。 3. 其他型別使用 SameValueNonNumeric 演算法。 :::spoiler 補充:SameValueNonNumeric 演算法 - 值為 null 或 undefined,回傳 true。 - String、Boolean、Symbol、Object 型別比較值是否相同。 ::: ### ++SameValueZero++ 1. 比較型別是否相同,不同就回傳 false。 2. 型別是 Number 或 BigInt ,**進行 Type(x)::sameValueZero(x, y) 的比較**。++兩方的值是 NaN,回傳 true,這是 includes 能夠解決 NaN 不等於 NaN 的原因++。 3. 其他型別使用 SameValueNonNumeric 演算法。 :::spoiler 補充:`Type(x)::sameValueZero(x, y)` - `Type(x)::sameValueZero(x, y)`:每種內建型別定義許多 operations,而 Number、BigInt 是 ECMAScript 內建的 Numeric 型別,其中的 operations 是 T::sameValueZero(x, y)。 - 兩方的值是 NaN,回傳 true,這是 includes 能夠解決 NaN 不等於 NaN 的原因。 ::: 元素型別為 Object 時,需要考慮值的參考 --- 元素型別為 Object,值相同但參考不同,indexOf 和 includes 回傳 false。 ```jsx let array = [{id: 1}, {id: 2}, {id: 3}]; /* 值相同,但參考不同 */ array.indexOf({id: 2}) !== -1 // false array.includes({id: 2}) // false ``` ```jsx let item = {id: 2}; let array = [{id: 1}, item, {id: 3}]; /* 值相同、參考相同 */ array.indexOf(item) !== -1 // true array.includes(item) // true ```