開発者ドキュメント

JavaScriptでの文字列と配列のindexOfメソッドの調査

配列または文字列内の要素を見つける必要がある場合、 indexOf() あなたの親友の一人です。

indexOf   配列内

最初にコードを記述し、後で説明します。

モジュール:findSpencer.js
const zoo = ['🐒', '🦄', '🐊', '🐸', '🐙'];
const spencersIndex = zoo.indexOf('🐊');
// spencersIndex === 2
const spencer = zoo[spencersIndex];
// spencer === '🐊'

最も単純なバージョンでは、 indexOf メソッドは、検索しようとしている要素である1つの引数を取ります。 次に、配列内で見つかった最初の要素のインデックスを返します。 el === target. これは、配列に2つの一致がある場合でも、indexOfは1つの結果のみを返すことを意味します。 結果は、配列内で最初に出現します(配列を左から右に読み取ります)。

配列内のどの項目も満たすものがない場合 el === target チェック、の値 -1 が返されます。

しかし、Skyler(Spencerの妹)も探しているとしましょう。 次に、オプションの引数を追加して、別のインデックスから検索を開始できます。

モジュール:findSkyler.js
const zoo = ['🐒', '🦄', '🐊', '🐸', '🐙',  '🐊']; // Skyler just arrived!
const spencersIndex = zoo.indexOf('🐊'); // === 2 same as before

// We start searching after 
const skylersIndex = zoo.indexOf('🐊', spencersIndex + 1);
// skylersIndex === 5

indexOfに基づいてすべてのインデックスを返すArrayプロトタイプにメソッドを作成することもできます。

モジュール:indexesOf.js
// Try to think of ways to make indicesOf more performant
Array.prototype.indicesOf = function (target) {
  const result = [];
  let currentIndex = 0;
  while(true) {
    // here this ===  the array on which we call `indicesOf`
    const targetIndex = this.indexOf(target, currentIndex);
    if (targetIndex == -1)
      break;

    result.push(targetIndex);

    currentIndex = targetIndex +1;
  }

  return result;
}
const zoo = ['🐒', '🦄', '🐊', '🐸', '🐙',  '🐊']; // Skyler just arrived!
const alligatorsIndices = zoo.indicesOf('🐊');
// alligatorsIndices returns [2, 5]

indexOfで何が見つかりませんか?

トリプルイコール比較を使用して検索を中断していることに気付いたかもしれません el === target これは厳密な等式比較です。 これは、たとえば、参照以外では配列、オブジェクト、または関数をテストできないことを意味します。

const simpleArray = [1, 2, 3];
const simpleFunction = () => {console.log('hey')};
const simpleObject = {alligator: 'cage'};

const compositeArray = [simpleArray, simpleFunction, simpleObject];

// These all work as expected because we compare by reference
compositeArray.indexOf(simpleArray); // returns 0
compositeArray.indexOf(simpleFunction); // returns 1
compositeArray.indexOf(simpleObject); // returns 2

// These won't work 
compositeArray.indexOf([1, 2, 3]); // returns -1
compositeArray.indexOf(() => {console.log('hey')}); // returns -1
compositeArray.indexOf({alligator: 'cage'}) // returns -1

深いindexOf

オブジェクト、配列、関数も再帰的にチェックするユーティリティを作成するとします。

モジュール:inDepthIndexOf.js
Array.prototype.deepIndexOf = function (target) {
  // If the target is an object, array or a function, we give it a special treatment
  if (typeof target === 'object' || typeof target === 'function') {
    // We stringify the target 
    const searchTarget = target.toString()
    // We loop through all of the elements of the array
    for (let index = 0; index < this.length; index++){
      const element = this[index]
      // We check if the element in the array is an object or a function AND if so we check if its' stringified value is equal to our target
      if ((typeof element === 'object' || typeof target === 'function') && element.toString() === searchTarget) {
        // if we have a match we interrupt the loop and return the index
        return index
      }
    }
    // if nothing matched we return -1
    return -1
  }
  return this.indexOf(target)
}

const simpleArray = [1, 2, 3];
const simpleFunction = () => {console.log('hey')};
const simpleObject = {alligator: 'cage'};

const compositeArray = [simpleArray, simpleFunction, simpleObject];

// These all work as expected because we compare by reference
compositeArray.deepIndexOf(simpleArray); // returns 0
// ... You know the rest
// These will work!
compositeArray.deepIndexOf([1, 2, 3]); // returns 0
compositeArray.deepIndexOf(() => {console.log('hey')}); // returns 1
compositeArray.deepIndexOf({alligator: 'cage'}) // returns 2

このコードを改善する方法はたくさんあります。 手元に時間があれば、より正確でパフォーマンスの高いものにする方法を考えてみてください。 Twitterであなたのアイデアを読んでみたいです。

パフォーマンス

使用する indexOf 単に行うよりもはるかに遅い for loop. それはそれを意味するものではありません indexOf 遅い。 配列が小さい場合、indexOf()とforループの違いはわかりません。 配列が非常に大きいために2つの方法の違いに気付く場合は、配列が非常に大きい理由と、検索を最適化する方法について疑問に思うはずです。 パフォーマンスベンチマークはJSPerfにあります。

var spencersIndex
// This is faster than indexOf('🐊') but it is much uglier
for(var index = 0; index < zoo.length; index ++) {
  if (zoo[index] === '🐊')
    spencersIndex = index
}
// spencers Index === 2

indexOf 文字列で

からすべてのロジックを移植できます Array.indexOf このセクションに。 コーディングしましょう!

モジュール:whereIsSpencer.js
const whereIsSpencer = "We are all looking for Spencer the alligator. Spencer is a dear friend. Lookout here comes 🐊!"

const spencersIndex = whereIsSpencer.indexOf('Spencer');
// spencersIndex ===  23

// to find find the second occurence of 'Spencer',
// we need to add one to the position of spencer #1
const secondSpencerIndex = whereIsSpencer.indexOf('Spencer', spencersIndex + 1);
// secondSpencerIndex ===  46

const alligatorIndex = whereIsSpencer.indexOf('🐊');
// alligatorIndex ===  91

// Be careful the search is case sensitive!
const lowerCaseSpencer = whereIsSpencer.indexOf('spencer');
// lowerCaseSpencer === -1

今、私たちは同じものを作成することができます indicesOf のための機能 Array.prototype.string.

モジュール:indexesOfStrings.js
// This is a bit more concise than the previous indicesOf function
// But it is exactly the same logic
String.prototype.indicesOf = function (target) {
  let currentIndex = this.indexOf(target);
  const allIndices = []
  while(currentIndex != -1) {
    allIndices.push(currentIndex);
    currentIndex =  this.indexOf(target, currentIndex +1 );
  }

  return allIndices;
}

const whereIsSpencer = "We are all looking for Spencer the alligator. Spencer is a dear friend. Lookout here comes 🐊!";

const spencerIndices = whereIsSpencer.indicesOf('Spencer');
// spencerIndices equals [23, 46]

この投稿を楽しんでいただけたでしょうか。 ご提案、ご質問、ご意見がございましたら、Twitterまでお気軽にお問い合わせください。

モバイルバージョンを終了