例:
var arr = ["one","two","three"];
arr.forEach(function(part){
part = "four";
return "four";
})
alert(arr);
配列はまだ元の値のままですが、反復関数から配列の要素に書き込みアクセスする方法はありますか?
x=[2,3,4]; x=x.map(n=>n*2); // [4,6,8]
例:
var arr = ["one","two","three"];
arr.forEach(function(part){
part = "four";
return "four";
})
alert(arr);
配列はまだ元の値のままですが、反復関数から配列の要素に書き込みアクセスする方法はありますか?
x=[2,3,4]; x=x.map(n=>n*2); // [4,6,8]
回答:
コールバックには、要素、インデックス、および配列自体が渡されます。
arr.forEach(function(part, index, theArray) {
theArray[index] = "hello world";
});
編集 —コメントに記載されているように、.forEach()
関数は2番目の引数を取ることができthis
、コールバックへの各呼び出しでの値として使用されます。
arr.forEach(function(part, index) {
this[index] = "hello world";
}, arr); // use arr as this
この2番目の例は、コールバックのarr
ようthis
に設定されていることを示しています。.forEach()
呼び出しに含まれる配列はのデフォルト値であると考えるかもしれませんが、this
何らかの理由でそうではありません。this
なりundefined
、第2引数が提供されていない場合。
(注:this
コールバックが=>
関数の場合、上記のものは適用されませんthis
。そのような関数が呼び出されたときに何にもバインドされないためです。)
また、Arrayプロトタイプには同様のユーティリティのファミリー全体が提供されていることを覚えておくことも重要です。最適な解決策は単に別のツールを選択することであるかのように、Stackoverflowで1つの関数または別の関数について多くの質問が表示されることです。あなたが持っています:
forEach
配列のすべてのエントリで、またはすべてのエントリに対して処理を行うため。filter
適格なエントリのみを含む新しい配列を生成するため。map
既存の配列を変換して1対1の新しい配列を作成するため。some
配列内の少なくとも1つの要素が何らかの説明に適合するかどうかを確認します。every
配列内のすべてのエントリが説明と一致するかどうかを確認します。find
配列の値を探す等々。MDNリンク
part
(またはo
es6 でも)未定義ですか?反復値を取得する方法?
part
はundefined
、配列の要素がundefined
明示的に割り当てられている場合です。配列(値が割り当てられていない配列エントリ)の「空の」スロットは、.forEach()
他のほとんどの配列反復メソッドによってスキップされます。
.forEach()
期すために、2番目の引数も取ります。これは、コールバック内でthisArg
使用できthis
ます。注:これ.forEach
は、コールバックの引数ではなく、引数です。
this
渡された2番目の引数を.forEach()
使用するには、構文を使用してコールバック関数を渡す必要がありますfunction()
。これは、ES6の矢印関数を使用() => {}
してもコンテキストがバインドされないためです。
レッツトライそれをシンプルに保つ、それが実際に働いているか議論します。変数の型と関数のパラメーターに関係しています。
これが私たちが話しているあなたのコードです:
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、文字列、ブール、数値)は実際の値を格納します。
例: var x = 5;
参照タイプ(カスタムオブジェクト)は、オブジェクトのメモリロケーションを格納します。
例: var xObj = { x : 5 };
3番目に、関数パラメーターのしくみ。
関数では、パラメーターは常に値で渡されます。
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);
In functions, parameters are always passed by value.
2番目の例はどうですか?
配列:[1, 2, 3, 4]
結果:["foo1", "foo2", "foo3", "foo4"]
Array.prototype.map()
元の配列を保持const originalArr = ["Iron", "Super", "Ant", "Aqua"];
const modifiedArr = originalArr.map(name => `${name}man`);
console.log( "Original: %s", originalArr );
console.log( "Modified: %s", modifiedArr );
Array.prototype.forEach()
元の配列を上書きconst originalArr = ["Iron", "Super", "Ant", "Aqua"];
originalArr.forEach((name, index) => originalArr[index] = `${name}man`);
console.log( "Overridden: %s", originalArr );
let arr1 = ["1", 2, 3, 4]; arr1.map(function(v) { return "foo"+ v; }); console.log( arr );
Array.prototype.map()元の配列を変更しないでください。
map
は間違いなくその配列を変更できますがforEach
、一般的には変更しません。
ジャバスクリプトは、値によってパスされ、かつ本質的手段がpart
あるコピー配列内の値の。
値を変更するには、ループで配列自体にアクセスします。
arr[index] = 'new value';
part
はコピーされるかどうかのタイプに依存します-変数がポインターではなく値であることは正しいです
.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();
map()
代わりにを使用してくださいforEach()
。map()
ソース配列を反復処理し、元の[変更]コピーを含む新しい配列を返します。ソース配列は変更されません。
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が残ります。
これを覚えておいてください。
インデックスを変更する要素を完全に追加または削除するには、zhujy_8833の提案である、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'挿入を処理する必要があります。それ以外の方法は期待どおりに行われません。