例:
var arr = ["one","two","three"];
arr.forEach(function(part){
part = "four";
return "four";
})
alert(arr);
配列はまだ元の値のままですが、反復関数から配列の要素への書き込みアクセス権を持つ方法はありますか?
コールバックには要素、インデックス、そして配列そのものが渡されます。
arr.forEach(function(part, index, theArray) {
theArray[index] = "hello world";
});
edit - コメントに記載されているように、.forEach()
関数は2番目の引数を取ることができます。これは、コールバックを呼び出すたびにthis
の値として使用されます。
arr.forEach(function(part, index) {
this[index] = "hello world";
}, arr); // use arr as this
2番目の例では、コールバックでarr
自体がthis
として設定されています。 .forEach()
呼び出しに関わる配列はdefaultthis
の値かもしれませんが、何らかの理由でそうではありません。 2番目の引数が指定されていない場合、this
はundefined
になります。
また、Arrayプロトタイプには類似したユーティリティのファミリーがすべて用意されていることを覚えておくことも重要です。また、Stackoverflowではさまざまな質問がポップアップ表示されます。あなたは持っています:
forEach
は、配列内のすべてのエントリを使って、またはすべてのエントリに対して処理を行うためのものです。filter
。map
。some
。every
。find
等々。 MDNリンク
それを単純にして、それが実際にどのように機能するのかを議論するためにを試してみましょう。それは変数型と関数パラメータと関係があります。
これが私たちが話しているあなたのコードです:
var arr = ["one","two","three"];
arr.forEach(function(part) {
part = "four";
return "four";
})
alert(arr);
まずはじめに、ここでArray.prototype.forEach()について読むべきところです。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
次に、JavaScriptの値型について簡単に説明しましょう。
プリミティブ(未定義、null、String、Boolean、Number)は実際の値を格納します。
例:var x = 5;
参照型(カスタムオブジェクト)は、オブジェクトのメモリ位置を格納します。
例:var xObj = { x : 5 };
そして第三に、関数パラメータの働き。
関数では、パラメータは常に値で渡されます。
arr
は文字列の配列なので、プリミティブオブジェクトの配列です。つまり、値によって格納されます。
したがって、上記のコードでは、これは、forEach()が繰り返されるたびに、part
がarr[index]
、と同じ値になりますが、同じオブジェクトにはなりません。
part = "four";
はpart
変数を変更しますが、arr
はそのままにします。
次のコードはあなたが望む値を変更します:
var arr = ["one","two","three"];
arr.forEach(function(part, index) {
arr[index] = "four";
});
alert(arr);
配列arr
が参照型の配列である場合、参照型は実際のオブジェクトではなくオブジェクトのメモリ位置を格納するため、次のコードが機能します。
var arr = [{ num : "one" }, { num : "two"}, { num : "three"}];
arr.forEach(function(part, index) {
// part and arr[index] point to the same object
// so changing the object that part points to changes the object that arr[index] points to
part.num = "four";
});
alert(arr[0].num);
alert(arr[1].num);
alert(arr[2].num);
以下は、part
に格納されているオブジェクトをそのままにして、arr
を新しいオブジェクトを指すように変更できることを示しています。
var arr = [{ num : "one" }, { num : "two"}, { num : "three"}];
arr.forEach(function(part, index) {
// the following will not change the object that arr[index] points to because part now points at a new object
part = 5;
});
alert(arr[0].num);
alert(arr[1].num);
alert(arr[2].num);
配列:["1", 2, 3, 4]
結果:["foo1", "foo2", "foo3", "foo4"]
Array.prototype.map()
元の配列を保持する新しい変数modifiedArr
を導入することによって達成される
const arr = ["1", 2, 3, 4];
const modifiedArr = arr.map(v => `foo${v}`);
console.log( "Original:", arr );
console.log( "Modified:", modifiedArr );
Array.prototype.forEach()
元の配列を修正するそのキーをインデックスarr[i]
でターゲティングすることによって達成される
const arr = ["1", 2, 3, 4];
arr.forEach((v, i) => arr[i] = `foo${v}`);
console.log( "Original:", arr );
Javascriptは値渡しであり、これは基本的にpart
が配列内の値のコピーコピーであることを意味します。
値を変更するには、ループ内で配列自体にアクセスします。
arr[index] = 'new value';
.forEach関数はコールバック関数(eachelement、elementIndex)を持つことができるので、基本的にあなたがする必要があるのは以下の通りです。
arr.forEach(function(element,index){
arr[index] = "four"; //set the value
});
console.log(arr); //the array has been overwritten.
または、元の配列を保持したい場合は、上記の手順を実行する前にそのコピーを作成することができます。コピーするには、次のようにします。
var copy = arr.slice();
配列のインデックスに置き換えます。
array[index] = new_value;
これは=>
スタイルの関数を使った同様の答えです。
var data = [1,2,3,4];
data.forEach( (item, i, self) => self[i] = item + 10 );
結果を出します。
[11,12,13,14]
self
パラメータは、矢印スタイル関数では必ずしも必要ではないので、
data.forEach( (item,i) => data[i] = item + 10);
また働きます。
Arrayオブジェクトメソッドでは、基本的なforループと比較してもArrayコンテンツを変更できますが、これらのメソッドには重要な機能が1つ欠けています。実行時にインデックスを変更することはできません。
たとえば、現在の要素を削除して同じ配列内の別のインデックス位置に配置する場合は、これを簡単に実行できます。現在の要素を前の位置に移動しても、次の繰り返しで問題は発生しません。何もしていない場合と同じ次の項目が表示されます。
このコードを考えてみましょう。ここで、インデックスが5までカウントしたら、インデックス位置5のアイテムをインデックス位置2に移動します。
var ar = [0,1,2,3,4,5,6,7,8,9];
ar.forEach((e,i,a) => {
i == 5 && a.splice(2,0,a.splice(i,1)[0])
console.log(i,e);
}); // 0 0 - 1 1 - 2 2 - 3 3 - 4 4 - 5 5 - 6 6 - 7 7 - 8 8 - 9 9
しかし、現在の要素を現在のインデックス位置を超えた場所に移動すると、少し面倒になります。それから、次のアイテムは移動したアイテムの位置に移動し、次の反復ではそれを見たり評価したりすることはできなくなります。
このコードを考えてみましょう。ここでは、インデックスが5までカウントしたら、インデックス位置5のアイテムをインデックス位置7に移動します。
var a = [0,1,2,3,4,5,6,7,8,9];
a.forEach((e,i,a) => {
i == 5 && a.splice(7,0,a.splice(i,1)[0])
console.log(i,e);
}); // 0 0 - 1 1 - 2 2 - 3 3 - 4 4 - 5 5 - 6 7 - 7 5 - 8 8 - 9 9
だから私たちはループで6に会ったことがない。通常、forループでは、次の実行でインデックスが同じ位置に留まるように配列アイテムを前方に移動すると、インデックス値が減少し、削除されたアイテムの場所に移動したアイテムを評価できます。これは配列メソッドでは不可能です。あなたはインデックスを変更することはできません。次のコードを確認してください
var a = [0,1,2,3,4,5,6,7,8,9];
a.forEach((e,i,a) => {
i == 5 && (a.splice(7,0,a.splice(i,1)[0]), i--);
console.log(i,e);
}); // 0 0 - 1 1 - 2 2 - 3 3 - 4 4 - 4 5 - 6 7 - 7 5 - 8 8 - 9 9
i
をデクリメントするとわかるように、5から6ではなく、残ったところから続きます。
だからこれを覚えておいてください。
Sliceを拡張してコピーを繰り返すためにインデックスを変更する要素を完全に追加または削除するには、単に削除または追加した要素の数を数え、それに応じてインデックスを変更します。たとえば、要素を削除するには
let values = ["A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8"];
let count = 0;
values.slice().forEach((value, index) => {
if (value === "A2" || value === "A5") {
values.splice(index - count++, 1);
};
});
console.log(values);
// Expected: [ 'A0', 'A1', 'A3', 'A4', 'A6', 'A7', 'A8' ]
前に要素を挿入するには:
if (value === "A0" || value === "A6" || value === "A8") {
values.splice(index - count--, 0, 'newVal');
};
// Expected: ['newVal', A0, 'A1', 'A2', 'A3', 'A4', 'A5', 'newVal', 'A6', 'A7', 'newVal', 'A8' ]
後に要素を挿入するには:
if (value === "A0" || value === "A6" || value === "A8") {
values.splice(index - --count, 0, 'newVal');
};
// Expected: ['A0', 'newVal', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'newVal', 'A7', 'A8', 'newVal']
要素を置き換えるには:
if (value === "A3" || value === "A4" || value === "A7") {
values.splice(index, 1, 'newVal');
};
// Expected: [ 'A0', 'A1', 'A2', 'newVal', 'newVal', 'A5', 'A6', 'newVal', 'A8' ]
注: 'before'挿入と 'after'挿入の両方を実装している場合、コードは 'before'挿入を最初に処理する必要があります。それ以外の方法は予想どおりにはなりません。