web-dev-qa-db-ja.com

JavaScriptで[] .forEach.call()は何をしますか?

コードのスニペットを見ていましたが、空の配列にforEachが適用されたノードリストで関数を呼び出す複数の要素が見つかりました。

たとえば、次のようなものがあります。

[].forEach.call( document.querySelectorAll('a'), function(el) {
   // whatever with the current node
});

しかし、私はそれがどのように機能するのか理解できません。 forEachの前にある空の配列の動作とcallの動作を誰にも説明できますか?

111
Mimo

querySelectorAllメソッドNodeListを返します。これは配列に似ていますが、配列ではありません。したがって、forEachメソッドはありません(配列オブジェクトはArray.prototypeを介して継承します)。

NodeListは配列に似ているため、配列メソッドは実際に動作します。したがって、[].forEach.callを使用することで、NodeListのコンテキストでArray.prototype.forEachメソッドを呼び出します。単にyourNodeList.forEach(/*...*/)を実行できたかのように。

空の配列リテラルは、展開されたバージョンへのショートカットにすぎないことに注意してください。

Array.prototype.forEach.call(/*...*/);
48
James Allardice

他の回答はこのコードを非常によく説明しているので、提案を追加します。

これは、簡単かつ明確にするためにリファクタリングする必要があるコードの良い例です。これを行うたびに[].forEach.call()またはArray.prototype.forEach.call()を使用する代わりに、それから単純な関数を作成します。

function forEach( list, callback ) {
    Array.prototype.forEach.call( list, callback );
}

より複雑で曖昧なコードの代わりに、この関数を呼び出すことができます:

forEach( document.querySelectorAll('a'), function( el ) {
   // whatever with the current node
});
20
Michael Geary

を使用してより良く書くことができます

Array.prototype.forEach.call( document.querySelectorAll('a'), function(el) {

});

document.querySelectorAll('a')は、配列に似たオブジェクトを返しますが、Array型を継承しません。したがって、document.querySelectorAll('a')によって返される値としてコンテキストを使用して、Array.prototypeオブジェクトからforEachメソッドを呼び出します。

5
Arun P Johny

私がいつも使っている、ただの汚い解決策です。良いプラクティスと同じように、プロトタイプには触れません。もちろん、これを改善する方法はたくさんありますが、アイデアは得られます。

const forEach = (array, callback) => {
  if (!array || !array.length || !callback) return
  for (var i = 0; i < array.length; i++) {
    callback(array[i], i);
  }
}

forEach(document.querySelectorAll('.a-class'), (item, index) => {
  console.log(`Item: ${item}, index: ${index}`);
});

1行追加するだけです:

NodeList.prototype.forEach = HTMLCollection.prototype.forEach = Array.prototype.forEach;

そして出来上がり!

document.querySelectorAll('a').forEach(function(el) {
  // whatever with the current node
});

楽しい :-)

警告: NodeListはグローバルクラスです。パブリックライブラリを作成する場合は、この推奨事項を使用しないでください。ただし、Webサイトまたはnode.jsアプリで作業する場合、自己効力感を高めるための非常に便利な方法です。

1
imos

空の配列のプロトタイプには、FunctionオブジェクトであるforEachプロパティがあります。 (空の配列は、すべてのforEachオブジェクトが持つArray関数への参照を取得する簡単な方法です。関数オブジェクトは、同様にcallプロパティを持ちます。関数。関数のcall関数を呼び出すと、指定された引数で関数が実行されます。最初の引数は、呼び出された関数でthisになります。

call関数のドキュメントを見つけることができます hereforEachのドキュメントは here です。

1
Ted Hopp

[]は常に新しい配列を返します。new Array()と同等ですが、Arrayはユーザーによって上書きされる可能性がありますが、[]は上書きできないため、配列を返すことが保証されます。したがって、これはArrayのプロトタイプを取得する安全な方法であり、次に説明したように、callを使用してarraylike nodelist(this)で関数を実行します。

この値と引数を個別に指定して関数を呼び出します。 mdn

0
Xotic750

この古い質問について更新したい:

最新のブラウザで[].foreach.call()を使用して要素をループする理由はほとんど終わりました。 document.querySelectorAll("a").foreach()を直接使用できます。

NodeListオブジェクトはノードのコレクションであり、通常はNode.childNodesなどのプロパティとdocument.querySelectorAll()などのメソッドによって返されます。

NodeListは配列ではありませんが、forEach()で繰り返し処理することができます。 Array.from()を使用して実際の配列に変換することもできます。

ただし、一部の古いブラウザーはNodeList.forEach()もArray.from()も実装していません。これは、Array.prototype.forEach()を使用して回避できます。このドキュメントの例を参照してください。

0

Norguard 説明[].forEach.call()が行うこと James Allardiceなぜそれを行うのか:querySelectorAllはforEachメソッドを持たないNodeListを返すため...

Chrome 51 +、Firefox 50 +、Opera 38、Safari 10などの最新のブラウザを使用している場合を除きます。

そうでない場合は、 Polyfill を追加できます:

if (window.NodeList && !NodeList.prototype.forEach) {
    NodeList.prototype.forEach = function (callback, thisArg) {
        thisArg = thisArg || window;
        for (var i = 0; i < this.length; i++) {
            callback.call(thisArg, this[i], i, this);
        }
    };
}
0
Mikel