web-dev-qa-db-ja.com

Javascript .filter()メソッドでコールバック関数に追加のパラメーターを渡すにはどうすればよいですか?

配列内の各文字列を特定の文字列と比較したい。私の現在の実装は次のとおりです。

function startsWith(element) {
    return element.indexOf(wordToCompare) === 0;
}
addressBook.filter(startsWith);

この単純な関数は動作しますが、これはwordToCompareがグローバル変数として設定されているためだけですが、もちろんこれを避けてパラメーターとして渡したいと思います。私の問題は、startsWith()を定義する方法がわからないため、余分なパラメーターを1つ受け入れることです。これは、デフォルトのパラメーターがどのように渡されるかを本当に理解していないためです。考えられるさまざまな方法をすべて試しましたが、どれも機能しません。

'ビルトイン'コールバック関数に渡されたパラメーターがどのように機能するのかを説明できたら(申し訳ありませんが、これらのより良い用語はわかりません)

94
agente_secreto

startsWithがWordを受け入れて比較するようにし、関数を返します。これはフィルター/コールバック関数として使用されます。

function startsWith(wordToCompare) {
    return function(element) {
        return element.indexOf(wordToCompare) === 0;
    }
}

addressBook.filter(startsWith(wordToCompare));

別のオプションは Function.prototype.bind[MDN] (ECMAScript 5をサポートするブラウザーでのみ使用可能、古いブラウザーのシムのリンクをたどる)、最初の引数を「修正」する:

function startsWith(wordToCompare, element) {
    return element.indexOf(wordToCompare) === 0;
}

addressBook.filter(startsWith.bind(this, wordToCompare));

私はそれが取るデフォルトパラメータがどのように渡されるのか本当に理解していない

それについて特別なことは何もありません。ある時点で、filterはコールバックを呼び出して、配列の現在の要素を渡すだけです。したがって、それは別の関数を呼び出す関数です。この場合、引数として渡すコールバックです。

同様の関数の例を次に示します。

function filter(array, callback) {
    var result = [];
    for(var i = 0, l = array.length; i < l; i++) {
        if(callback(array[i])) {  // here callback is called with the current element
            result.Push(array[i]);
        }
    }
    return result;
}
140
Felix Kling

フィルターの2番目のパラメーターは、コールバック内でthisを設定します。

arr.filter(callback[, thisArg])

そのため、次のようなことができます。

function startsWith(element) {
    return element.indexOf(this) === 0;
}
addressBook.filter(startsWith, wordToCompare);
93
Jeff
function startsWith(element, wordToCompare) {
    return element.indexOf(wordToCompare) === 0;
}

// ...
var Word = "SOMETHING";

addressBook.filter(function(element){
    return startsWith(element, Word);
});
11
James Montagne

矢印関数を使用してES6の代替を探している人のために、次のことができます。

let startsWith = wordToCompare => (element, index, array) => {
  return element.indexOf(wordToCompare) === 0;
}

// where Word would be your argument
let result = addressBook.filter(startsWith("Word"));

includes を使用して更新されたバージョン:

const startsWith = wordToCompare => (element, index, array) => {
  return element.includes(wordToCompare);
}
7
jhamPac

次のように、フィルター内で矢印関数を使用できます。

result = addressBook.filter(element => element.indexOf(wordToCompare) === 0);

MDNの矢印関数

矢印関数式は、関数式と比較して構文が短く、this値を字句的にバインドします(独自のthis、arguments、super、またはnew.targetをバインドしません)。矢印関数は常に匿名です。これらの関数式は非メソッド関数に最適であり、コンストラクターとして使用することはできません。

3
oddRaven

太い矢印関数が_[, thisArg]_を無視している理由を知りたい場合は、たとえばなぜ

["DOG", "CAT", "DOG"].filter(animal => animal === this, "DOG")は_[]_を返します

これは、これらの矢印関数内のthisは、関数の作成時にバインドされ、より広い範囲でthisの値に設定されるため、thisArg引数は無視されるためです。親スコープで新しい変数を宣言することで、これを簡単に回避できました。

let bestPet = "DOG"; ["DOG", "CAT", "DOG"].filter(animal => animal === bestPet); => ["DOG", "DOG"]

いくつかの参考文献へのリンクを次に示します。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this

1
Jimmy Kettler

フィルター関数を使用して、すべてのパラメーターにアクセスし、複雑になりすぎないようにする簡単な方法があります。

コールバックのthisArgが別のスコープフィルターに設定されない限り、フィルターは独自のスコープを作成せず、現在のスコープ内のparamsにアクセスできます。必要に応じて他の値にアクセスするために「this」を設定して別のスコープを定義できますが、デフォルトでは呼び出し元のスコープに設定されます。 thisがAngular scopes このスタック内 に使用されていることがわかります。

IndexOfを使用すると、フィルターの目的が無効になり、オーバーヘッドが増えます。フィルターは既に配列を通過しているのに、なぜ繰り返し処理する必要があるのですか?代わりに、単純な 純粋な関数 にすることができます。

状態にitemsと呼ばれる配列があるReactクラスメソッド内のユースケースシナリオは、既存の状態を確認できるフィルター:

checkList = (item) => {  // we can access this param and globals within filter
  var result = this.state.filter(value => value === item); // returns array of matching items

  result.length ? return `${item} exists` : this.setState({
    items: items.Push(item) // bad practice, but to keep it light
  });
}
0
DBrown

oddRavenの回答と https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter に基づく

私はそれを2つの異なる方法でやった。 1)関数wayを使用します。 2)インライン方法を使用します。

//Here  is sample codes : 

var templateList   = [
{ name: "name1", index: 1, dimension: 1 }  ,
{ name: "name2", index: 2, dimension: 1 }  ,
{ name: "name3", index: 3, dimension: 2 }  ];


//Method 1) using function : 

function getDimension1(obj) {
                if (obj.dimension === 1) // This is hardcoded . 
                    return true;
                else return false;
            } 

var tl = templateList.filter(getDimension1); // it will return 2 results. 1st and 2nd objects. 
console.log(tl) ;

//Method 2) using inline way 
var tl3 = templateList.filter(element => element.index === 1 || element.dimension === 2  ); 
// it will return 1st and 3rd objects 
console.log(tl3) ;
0
Ashish