JS配列の基本的な操作--配列遍歴にはいったい何種類の方法がありますか?


1回の面接から、一緒に面接した同僚は面接者に質問しました.配列はどのような方法がありますか.配列操作は普段から開発されているスキルだと思いますが、面接者はペロリと2つの方法を話したのでしょうか、最後に淘汰されました(面接者は真面目な妹紙で、面接は簡単にメモを取っていますが、基礎は確かに難しいですね~).
「配列遍歴」という質問には、答えが広く、一定の数の方法を列挙したり、違いを説明したりできるかどうかが鍵です.本稿では,配列の基本的な遍歴動作と高次関数について述べる.

一、配列基本遍歴


このセクションでは、最も一般的な4つの遍歴方法について説明します.

1.for...in


for...inは実はオブジェクトの遍歴方式で、配列専用ではなく、forを使用しています...inオブジェクト自体を巡回するすべての列挙可能な属性と、オブジェクトがそのコンストラクション関数のプロトタイプから継承する属性をObjectと巡回する.keys()関数が取得したリストは一致しています.
このメソッドでは、配列内の数値の下にない要素を巡回し、空の要素は無視されます.
let list = [7, 5, 2, 3]
list[10] = 1
list['a'] = 1
console.log(JSON.stringify(Object.keys(list)))

for (let key in list) {
  console.log(key, list[key])
}

出力:
> ["0","1","2","3","10","a"]
> 0, 7
> 1, 5
> 2, 2
> 3, 3
> 10, 1
> a, 1

この方法は配列を遍歴するのが最もピットであり,通常は秩序として表現されるが,オブジェクトの列挙順序,すなわち仕様によって順序が規定されていないため,具体的な実装はブラウザによって行われる.MDNドキュメントでは、「その遍歴順序に依存しない」ことを明確に推奨しています.

2.for...of


この方法は、配列が秩序化され、配列の値が反復される反復可能なオブジェクトの反復に使用されます.このメソッドでは、数値以外の下付き要素は巡回されず、配列の空の要素は無視されません.
let list = [7, 5, 2, 3]
list[5] = 4
list[4] = 5
list[10] = 1
//     6、7、8、9    
list['a'] = 'a'

for (let value of list) {
  console.log(value)
}

出力:
> 7
> 5
> 2
> 3
> 5
> 4
>   //      
>  //      
>  //      
>  //      
> 1

3.配列長を巡回する


この方法と方法2は,空の要素を無視することなく秩序化されているように比較される.
let list = ['a', 'b', 'c', 'd']
list[4] = 'e'
list[10] = 'z'
list['a'] = 0

for (let idx = 0; idx < list.length; idx++) {
  console.log(idx, list[idx])
}

出力:
> 0, a
> 1, b
> 2, c
> 3, d
> 4, e
> 5, //   
> 6, 
> 7, 
> 8, 
> 9, 
> 10, z

4.forEach遍歴


forEachは配列の高次関数で、次のように使用されます.
arr.forEach(callback[, thisArg])

パラメータの説明:
callbackは、配列内の要素ごとに実行される関数です.この関数は、3つのパラメータを受信します.
  • currentValue

  • 配列内で処理されている現在の要素.
  • indexオプション
  • 配列内で処理されている現在の要素のインデックス.
  • arrayオプション
  • forEach()メソッドが動作している配列.
    このArgはオプションのパラメータです.コールバック関数を実行するときにthisの値(参照オブジェクト)として使用します.
    forEachループ配列は配列の下にある昇順にループし、空の要素は無視されます.
    let list = ['a', 'b', 'c', 'd']
    list[4] = 'e'
    list[10] = 'z'
    list['a'] = 0
    
    list.forEach((value, key, list) => {
      console.log(key, value)
    })

    出力:
    > 0, a
    > 1, b
    > 2, c
    > 3, d
    > 4, e
    > 10, z

    無視しやすい詳細があります.配列を削除する要素をできるだけ避けるべきです.そうしないと、意外な状況が発生し、異なる遍歴方法では異なる表現があります.

    for...ofとforEach遍歴で要素を削除


    例えばfor...of遍歴で要素を削除するには:
    let list = ['a', 'b', 'c', 'd']
    
    for (let item of list) {
      if (item === 'a') {
        list.splice(0, 1)
      }
      console.log(item)
    }

    出力:
    > a
    > c
    > d

    forEach遍歴で要素を削除するには:
    let list = ['a', 'b', 'c', 'd']
    
    list.forEach((item, idx) => {
      if (item === 'a') {
        list.splice(0, 1)
      }
      console.log(item)
    })

    出力:
    > a
    > c
    > d

    両者は一致し,aまで遍歴するとaを削除するとbはスキップされ,増加要素はやや異なることがわかる.

    for...ofとforEach遍歴で要素を追加


    for...of遍歴に要素を追加するには:
    let list = ['a', 'b', 'c', 'd']
    for (let item of list) {
      if (item === 'a') {
        list.splice(1, 0, 'e')
      }
      console.log(item)
    }

    出力:
    > a
    > e
    > b
    > c
    > d

    forEach遍歴に要素を追加するには:
    let list = ['a', 'b', 'c', 'd']
    
    list.forEach((item, idx) => {
      if (item === 'a') {
        list.splice(1, 0, 'e')
      }
      console.log(item)
    })

    出力:
    > a
    > e
    > b
    > c

    あれ、「d」が少なくなった!実際にはforEachの遍歴回数は最初から決定されているので、最後の「d」は出力されません.これはforEachとfor遍歴配列の違いであり、もう一つの重要な違いはforEachがbreak、continue、returnなどの中断サイクルを使用できないことです.forは使用できます.
    要するに、配列を巡る過程で、配列の操作に注意しなければならない.python、jsは似ている.2つの言語では、オブジェクト/辞書と配列が参照され、可変オブジェクトであるからだ.

    二、高次関数を利用して配列を遍歴する


    上記の4つは比較的標準的な遍歴方式ですが、JSには配列には多くの高次関数があります.これらの関数は実際には配列を遍歴する目的を達成することができますが、関数ごとに適用シーンが異なりますので、簡単に紹介します.

    1. map


    map()メソッドパラメータはforEachと全く同じであり,両者の違いはmapがコールバック関数の戻り値を収集して新しい配列を生成するだけである.たとえば、配列内の各要素の2倍を新しい配列に出力します.
    let list = [1, 2, 3, 4]
    let result = list.map((value, idx) => value * 2)
    console.log(result) //   [2,4,6,8]

    2.filter


    filter()パラメータはforEachと完全に一致しますが、callback関数は真の値または偽の値を返す必要があります.filter()メソッドは、callbackが真の値を返す(trueとは異なる)すべての要素を含む新しい配列を作成します.たとえば、配列内の偶数をフィルタします.
    let list = [1, 2, 3, 4]
    let result = list.filter((value, idx) => value % 2 === 0)
    console.log(result) //   [2,4]

    3. find/findIndex


    find()メソッドは、配列内のcallbackがTruthyの値を返す最初の要素の値を返し、なければundefinedを返します.配列の最初の偶数を見つけるなど、非常に簡単です.
    let list = ['1', '2', '3', '4']
    let result = list.find(value => value % 2 === 0)
    console.log(result) //    2

    findIndex()メソッドはfindメソッドと似ていますが、findIndexはcallbackの戻り値をTruthyとする最初の要素のインデックスを返し、要素に合致しない場合は-1を返します.たとえば、配列の最初の偶数の下付き文字を見つけます.
    let list = [1, 2, 3, 4]
    let result = list.findIndex(value => value % 2 === 0)
    console.log(result) //    1

    4.every/some


    両方の関数の受信パラメータは、上記の関数と同じで、ブール値を返します.everyは、配列の各項目がcallback戻り値をTruthyとするかどうかを判断するために使用され、someはcallback要素戻り値をTruthyとする少なくとも1つが存在するかどうかを判断するために使用される.
    let list = [1, 2, 3, 4]
    //              10
    let result = list.every(value => {
      return value < 10
    })
    console.log(result) //   true
    
    //           2
    result = list.every(value => {
      return value > 2
    })
    console.log(result) //   false
    
    //          1
    result = list.some(value => {
      return value === 1
    })
    console.log(result) //   true
    
    //            10  
    result = list.some(value => {
      return value > 10
    })
    console.log(result) //   false

    5.reduce/reduceRightアキュムレータ


    パラメータは他の関数とは異なります.callbackは、4つのパラメータを含む配列内の各値の関数を実行します.
  • accumulator

  • 累計器はコールバックの戻り値を累計する.前回コールバックを呼び出したときに返された累積値またはinitialValue(下を参照)です.
  • currentValue

  • 配列内で処理されている要素.
  • currentIndexオプション
  • 配列内で処理されている現在の要素のインデックス.initialValueが指定されている場合、開始インデックス番号は0、それ以外の場合は1です.
  • arrayオプション
  • reduce()を呼び出す配列
    initialValueは、callback関数を最初に呼び出したときの最初のパラメータの値としてオプションです.初期値が指定されていない場合は、配列の最初の要素が使用されます.初期値のない空の配列でreduceを呼び出すとエラーが表示されます.
    reduce()メソッドは、配列内の各要素に対して、指定したreducer関数(昇順実行)を実行し、その結果を単一の戻り値にまとめます.reduceRightは、遍歴順序が逆になるだけです.
    例えば、一般的なニーズの1つは、forEachとreduceを使用して簡単に実現できる構造のlistをツリー構造にすることです.リスト構造:
    let list = [
      {
        id: 1,
        parentId: ''
      },
      {
          id: 2,
          parentId: ''
      },
      {
          id: 3,
          parentId: 1
      },
      {
          id: 4,
          parentId: 2,
      },
      {
          id: 5,
        parentId: 3
      },
      {
          id: 6,
        parentId: 3
      }
    ]

    ツリー構造:
          
    [
        {
            "id":1,
            "parentId":"",
            "children":[
                {
                    "id":3,
                    "parentId":1,
                    "children":[
                        {
                            "id":5,
                            "parentId":3
                        },
                        {
                            "id":6,
                            "parentId":3
                        }
                    ]
                }
            ]
        },
        {
            "id":2,
            "parentId":"",
            "children":[
                {
                    "id":4,
                    "parentId":2
                }
            ]
        }
    ]

    reduceとforEachを使用してlistをツリー構造に変換します.
    function listToTree(srcList) {
      let result = []
      // reduce              ,   forEach  ,        
      let nodeInfo = list.reduce((data, node) => (data[node.id] = node, data), {})
    
     // forEach        
      srcList.forEach(node => {
        if (!node.parentId) {
          result.push(node)
          return
        }
        let parent = nodeInfo[node.parentId]
        parent.children = parent.children || []
        parent.children.push(node)
      })
      return result
    }

    以上が,本稿で配列遍歴をめぐって紹介した配列基本動作である.これらの高次関数は、実際には配列遍歴(someのcallbackのようにfalseを返す)に使用できますが、実際の使用では、ニーズに応じて異なる方法を選択する必要があります.
    そこで、面接で「配列遍歴にはいくつの方法がありますか?」この質問には、「10種類以上」と答えることができます.結局、本稿では12種類を紹介しました.
    最后に、JSは実は1门のとても愚かな言叶で、时にはあなたがそれに渡した事、それは言うことができなくて、意外にも人をののしることができます!信じない?コンソールに次の数式を入力してみます.
    (![]+{})[-~!+[]^-~[]]+([]+{})[-~!![]]

    Just for fun. あまりまじめにしないで~、~
    本文のオリジナル、私の個人のウェブサイトに先発します:http://wintc.top/site/article?postId=8、転載は出典を明記してください.