Array.prototype.filter()

filter() メソッドは、与えられた関数によって実装されたテストに合格したすべての配列からなる新しい配列を生成します。

構文

let newArray = arr.filter(callback(element[, index, [array]])[, thisArg])

引数

callback

配列の各要素に対して実行するテスト関数です。この関数が true を返した要素は残され、false を返した要素は取り除かれます。

この関数は3つの引数を受け付けます。

element
配列内で処理中の現在の要素です。
indexOptional
配列内で処理中の現在の要素の位置です。
arrayOptional
filter メソッドが実行されている配列です。
thisArgOptional
callback を実行するときに this として使用する値です。

返値

テストに合格した要素からなる新しい配列です。テストに合格した要素がなかった場合は、空の配列が返されます。

解説

filter() は、与えられた callback 関数を配列の各要素に対して一度ずつ呼び出し、callbacktrue と評価される値を返したすべての要素からなる新しい配列を生成します。callback は値が代入されている配列の添字に対してのみ呼び出されます。つまり、すでに削除された添字や、まだ値が代入されていない添字に対しては呼び出されません。callback によるテストに合格しなかった配列要素は単純にスキップされ、新しい配列には含まれないだけです。

callback は 3 つの引数と共に呼び出されます。

  1. 要素の値
  2. 要素の添字
  3. 走査されている配列オブジェクト

filter に引数 thisArg が与えられた場合、そのオブジェクトは callback 関数内の this 値として使われます。そうでない場合、 undefinedthis 値として使われます。callback 関数内の最終的な this 値は関数内の this を決定する一般的ルールに従って決められます。

filter() は呼び出された配列を変化させません。

filter() によって処理される配列要素の範囲は、callback が最初に呼び出される前に設定されます。filter() の呼び出しが開始された後に (callback から) 追加された配列要素に対しては、callback は実行されません。既存の配列要素が削除された場合は、同様にそれらの要素は処理されません。

ポリフィル

filter() は ECMA-262 標準の第5版で追加されました。したがって、この標準のすべての実装に存在するとは限りません。

回避策として、スクリプトの最初に以下のコードを挿入して、ネイティブに対応していない ECMA-262 の実装で filter() を使用できるようにすることができます。このアルゴリズムは ECMA-262 第5版で指定されているものと完全に等価で、 fn.callFunction.prototype.bind() の元の値を評価し、 Array.prototype.push() が元の値を持つことを仮定しています。

if (!Array.prototype.filter){
  Array.prototype.filter = function(func, thisArg) {
    'use strict';
    if ( ! ((typeof func === 'Function' || typeof func === 'function') && this) )
        throw new TypeError();
   
    var len = this.length >>> 0,
        res = new Array(len), // preallocate array
        t = this, c = 0, i = -1;

    var kValue;
    if (thisArg === undefined){
      while (++i !== len){
        // checks to see if the key was set
        if (i in this){
          kValue = t[i]; // in case t is changed in callback
          if (func(t[i], i, t)){
            res[c++] = kValue;
          }
        }
      }
    }
    else{
      while (++i !== len){
        // checks to see if the key was set
        if (i in this){
          kValue = t[i];
          if (func.call(thisArg, t[i], i, t)){
            res[c++] = kValue;
          }
        }
      }
    }
   
    res.length = c; // shrink down array to proper size
    return res;
  };
}

小さい値をすべて取り除く

次の例では、filter() を使って 10 未満の値を持つ要素をすべて取り除いた配列を生成します。

function isBigEnough(value) {
  return value >= 10
}

let filtered = [12, 5, 8, 130, 44].filter(isBigEnough)
// filtered は [12, 130, 44]

配列内の素数をすべて検索する

以下の例は配列内のすべての素数を返します。

const array = [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]; 

function isPrime(num) {
  for (let i = 2; num > i; i++) {
    if (num % i == 0) {
      return false;
    }
  }
  return num > 1;
}

console.log(array.filter(isPrime)); // [2, 3, 5, 7, 11, 13]

JSON の不正な内容を取り除く

次の例では、filter() を使って id の数値が 0 以外の要素だけに絞った JSON を生成します。

let arr = [
  { id: 15 },
  { id: -1 },
  { id: 0 },
  { id: 3 },
  { id: 12.2 },
  { },
  { id: null },
  { id: NaN },
  { id: 'undefined' }
]

let invalidEntries = 0

function filterByID(item) {
  if (Number.isFinite(item.id) && item.id !== 0) {
    return true
  } 
  invalidEntries++
  return false;
}

let arrByID = arr.filter(filterByID)

console.log('Filtered Array\n', arrByID)
// Filtered Array
// [{ id: 15 }, { id: -1 }, { id: 3 }, { id: 12.2 }]

console.log('Number of Invalid Entries = ', invalidEntries)
// Number of Invalid Entries = 5

配列内の検索

次の例では filter() を使って検索条件で配列の絞り込みをしています。

let fruits = ['apple', 'banana', 'grapes', 'mango', 'orange']

/**
 * Filter array items based on search criteria (query)
 */
function filterItems(arr, query) {
  return arr.filter(function(el) {
      return el.toLowerCase().indexOf(query.toLowerCase()) !== -1
  })
}

console.log(filterItems(fruits, 'ap'))  // ['apple', 'grapes']
console.log(filterItems(fruits, 'an'))  // ['banana', 'mango', 'orange']

ES2015 版の実装

const fruits = ['apple', 'banana', 'grapes', 'mango', 'orange']

/**
 * Filter array items based on search criteria (query)
 */
const filterItems = (arr, query) => {
  return arr.filter(el => el.toLowerCase().indexOf(query.toLowerCase()) !== -1)
}

console.log(filterItems(fruits, 'ap'))  // ['apple', 'grapes']
console.log(filterItems(fruits, 'an'))  // ['banana', 'mango', 'orange']

初期の配列への影響 (変更、追加、削除)

以下の例は、配列が変更された時の filter の動作をテストするものです。

// Modifying each words
let words = ['spray', 'limit', 'exuberant', 'destruction','elite', 'present']

const modifiedWords = words.filter( (word, index, arr) => {
  arr[index+1] +=' extra'
  return word.length < 6
})

console.log(modifiedWords)
// Notice there are three words below length 6, but since they've been modified one is returned
// ["spray"]

// Appending new words
words = ['spray', 'limit', 'exuberant', 'destruction','elite', 'present']
const appendedWords = words.filter( (word, index, arr) => {
  arr.push('new')
  return word.length < 6
})

console.log(appendedWords)
// Only three fits the condition even though the `words` itself now has a lot more words with character length less than 6
// ["spray" ,"limit" ,"elite"]

// Deleting words
words = ['spray', 'limit', 'exuberant', 'destruction', 'elite', 'present']
const deleteWords = words.filter( (word, index, arr) => {
  arr.pop()
  return word.length < 6
})

console.log(deleteWords)
// Notice 'elite' is not even obtained as its been popped off `words` before filter can even get there
// ["spray" ,"limit"]

仕様書

仕様書
ECMAScript (ECMA-262)
Array.prototype.filter の定義

ブラウザーの互換性

Update compatibility data on GitHub
デスクトップモバイルサーバー
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewAndroid 版 ChromeAndroid 版 FirefoxAndroid 版 OperaiOSのSafariSamsung InternetNode.js
filterChrome 完全対応 1Edge 完全対応 12Firefox 完全対応 1.5IE 完全対応 9Opera 完全対応 9.5Safari 完全対応 3WebView Android 完全対応 ≤37Chrome Android 完全対応 18Firefox Android 完全対応 4Opera Android 完全対応 10.1Safari iOS 完全対応 1Samsung Internet Android 完全対応 1.0nodejs 完全対応 0.1.100

凡例

完全対応  
完全対応

関連情報