408

例:

var arr = ["one","two","three"];

arr.forEach(function(part){
  part = "four";
  return "four";
})

alert(arr);

配列はまだ元の値のままですが、反復関数から配列の要素への書き込みアクセス権を持つ方法はありますか?

4

11 に答える 11

634

コールバックには、要素、インデックス、および配列自体が渡されます。

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に関係する配列がデフォルト値であると思われるかもしれませんが、何らかの理由でそうではありません。その2番目の引数が提供されていない場合になります。.forEach()thisthisundefined

(注:コールバックが関数の場合、そのような関数が呼び出されたときに何にもバインドされないため、上記の内容thisは適用されません。)=>this

また、Arrayプロトタイプには同様のユーティリティのファミリー全体が提供されていることを覚えておくことが重要です。また、Stackoverflowには、ある関数または別の関数について多くの質問が表示されるため、別のツールを選択するのが最善の解決策です。あなたが持っている:

  • forEach配列内のすべてのエントリを使用して、またはすべてのエントリに対して何かを行うため。
  • filter適格なエントリのみを含む新しい配列を作成するため。
  • map既存の配列を変換して1対1の新しい配列を作成するため。
  • some配列内の少なくとも1つの要素が何らかの説明に適合するかどうかを確認します。
  • every配列内のすべてのエントリが説明と一致するかどうかを確認します。
  • find配列内の値を探す

等々。MDNリンク

于 2012-09-18T18:38:39.037 に答える
152

シンプルに保ち、実際にどのように機能しているかを説明しましょうそれは変数の型と関数のパラメータと関係があります。

これが私たちが話しているあなたのコードです:

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 };

そして第三に、関数パラメーターがどのように機能するか。

関数では、パラメーターは常に値によって渡されます。

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);
于 2015-07-08T16:23:27.240 に答える
125

配列:[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 );

于 2016-07-08T12:32:14.437 に答える
16

Javascriptは値渡しであり、これは基本的に配列内の値partコピーであることを意味します。

値を変更するには、ループ内の配列自体にアクセスします。

arr[index] = 'new value';

于 2012-09-18T18:38:02.467 に答える
8

=>スタイル関数を使用した同様の回答は次のとおりです。

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);

また動作します。

于 2019-02-27T23:56:04.340 に答える
3

配列のインデックスに置き換えます。

array[index] = new_value;
于 2012-09-18T18:39:54.527 に答える
3

.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();
于 2012-09-18T23:17:52.523 に答える
3

インデックスを変更する要素を完全に追加または削除するには、コピーを反復処理するためのslice()の提案のzhujy_8833の拡張により、すでに削除または追加した要素の数を数え、それに応じてインデックスを変更します。たとえば、要素を削除するには:

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' ]

注:「前」と「後」の両方の挿入を実装する場合、コードは「前」の挿入を最初に処理する必要があります。そうしないと、期待どおりになりません。

于 2018-11-19T11:19:02.087 に答える
2

Arrayオブジェクトメソッドを使用すると、配列のコンテンツを変更できますが、基本的なforループと比較すると、これらのメソッドには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から継続します。

したがって、これを覚えておいてください。

于 2016-05-15T18:23:41.090 に答える
1

アイテムを削除したい場合

行う必要のある変更が、リストから1つ以上のアイテムを完全に削除することである場合は、ループを使用してforループを逆方向に進む方が安全です。

    for (let i = myArray.length - 1; i >= 0; i--)
    {
        const item = myArray[i];

        if (...) 
        {
           // remove item
           // https://stackoverflow.com/questions/5767325/how-can-i-remove-a-specific-item-from-an-array?rq=1
        }
    };

逆方向に進むということは、各アイテムの配列が変更されないことを意味します。ループを進めて削除するitem[3]場合item[4]は、これが新しいitem[3]ものになります。これにより、何も簡単になりません。その問題が逆行することはありません。

もちろん、これはforeachを使用しないソリューションですが、「古い学校」の方法が最善である場合が多いことを覚えておくことが重要です。そして、何らかの理由break;でループから抜け出す必要がある場合(そして、少数のアイテムが存在する場合)、forループから抜け出すことができないため、forループの方が効率的です。

于 2021-08-26T20:53:21.583 に答える
0

オーバーライドしたい場合はこれを試すことができます

var newArray= [444,555,666];
var oldArray =[11,22,33];
oldArray.forEach((name, index) => oldArray [index] = newArray[index]);
console.log(newArray);
于 2020-05-12T11:36:08.387 に答える