JavaScript'te foreach yaparken dizinin değerlerini değiştirmek mümkün mü?


301

misal:

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

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

alert(arr);

Dizi hala orijinal değerleriyle, yineleme işlevinden dizi öğelerine yazma erişimine sahip olmanın herhangi bir yolu var mı?



Haritayı deneyin ( developer.mozilla.org/tr-TR/docs/Web/JavaScript/Reference/… ):x=[2,3,4]; x=x.map(n=>n*2); // [4,6,8]
Justin

Yanıtlar:


471

Geri arama öğesi, dizin ve dizinin kendisinden geçirilir.

arr.forEach(function(part, index, theArray) {
  theArray[index] = "hello world";
});

edit - bir yorumda belirtildiği gibi, .forEach()işlev this, geri aramaya yapılan her bir çağrının değeri olarak kullanılacak ikinci bir argüman alabilir :

arr.forEach(function(part, index) {
  this[index] = "hello world";
}, arr); // use arr as this

Bu ikinci örnek, geri aramadaki arrgibi ayarlandığını gösterir.Birisi this, .forEach()çağrıya dahil olan dizinin varsayılan değeri olabileceğini düşünebilir this, ancak herhangi bir nedenden dolayı değil; thisolacak undefinedo İkinci argüman sağlanmazsa.

(Not: thisgeri arama bir işlevse, yukarıdaki konular geçerli değildir =>, çünkü thisbu işlevler çağrıldığında hiçbir şeye bağlı değildir.)

Ayrıca, Array prototipinde sağlanan benzer yardımcı programların bir ailesinin olduğunu ve en iyi çözümün sadece farklı bir araç seçecek şekilde bir veya daha fazla işlev hakkında Stackoverflow üzerinde birçok sorunun ortaya çıktığını hatırlamak önemlidir. Şunlara sahipsiniz:

  • forEach bir dizideki her girdiyle veya bu girdiye bir şey yapmak için;
  • filter sadece nitelikli girişler içeren yeni bir dizi üretmek için;
  • map mevcut bir diziyi dönüştürerek bire bir yeni dizi oluşturmak için;
  • some bir dizideki en az bir öğenin açıklamaya uyup uymadığını kontrol etmek;
  • everybir dizideki tüm girişlerin bir açıklamayla eşleşip eşleşmediğini kontrol etmek ;
  • find dizideki bir değeri aramak için

ve bunun gibi. MDN bağlantısı


34
Teşekkürler! ES6: arr.forEach ((o, i, a) => a [i] = myNewVal)
DiegoRBaquero

neden part(hatta oes6'da) tanımsız? yinelenen değer nasıl elde edilir?
Daniil Mashkin

Dizinin bir öğesi açıkça atanmışsa @DaniilMashkin partolur . Bir dizinin "boş" yuvaları (hiçbir değer atanmamış bir dizi girişi) ve diğer dizi yineleme yöntemleri tarafından atlanır . undefinedundefined.forEach()
Sivri

2
Bütünlüğü sağlamak için, .forEach()aynı zamanda ikinci bir argüman alır thisArgsen olarak kullanabileceğiniz, thisgeri arama içeride. Not: bu bir argüman .forEachdeğil bir geri arama argümanı.
Yüce deve Moha

3
Kullanmak için thisikinci argüman olarak geçirilen .forEach()dizimini kullanarak geri çağırma işlevi geçmesi gerekiyor function()ES6 en ok işlevini kullanarak beri, () => {}bağlama bağlamı yok.
Ocak'ta

131

Diyelim deneyin basit tutmak ve aslında nasıl çalıştığını görüşmek üzere. Değişken tipleri ve fonksiyon parametreleri ile ilgilidir.

İşte bahsettiğiniz kod:

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

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

alert(arr);

Öncelikle, burada Array.prototype.forEach () hakkında okumanız gereken yer:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

İkinci olarak, JavaScript'teki değer türleri hakkında kısaca konuşalım.

Temel öğeler (undefined, null, String, Boolean, Number) gerçek bir değer depolar.

örn: var x = 5;

Referans Türleri (özel nesneler), nesnenin hafıza konumunu saklar.

örn: var xObj = { x : 5 };

Üçüncüsü, fonksiyon parametrelerinin nasıl çalıştığı.

Fonksiyonlarda, parametreler her zaman değere göre iletilir.

Çünkü arrYaylı bir dizi, bu bir dizi bu ilkel değere göre kaydedilmiş olur nesneleri.

Yukarıdaki kodunuz için bu, forEach () her tekrarlandığında , aynı nesneyepart eşit arr[index], ancak aynı nesneye eşit olmadığı anlamına gelir .

part = "four";partdeğişkeni değiştirecek , ama arryalnız kalacak .

Aşağıdaki kod istediğiniz değerleri değiştirir:

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

arr.forEach(function(part, index) {
  arr[index] = "four";
});

alert(arr);

Şimdi dizi arrbir dizi başvuru türüyse , aşağıdaki türler çalışır çünkü referans türleri gerçek nesne yerine bir nesnenin bellek konumunu depolar.

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

Aşağıda part, nesneleri arrtek başına depolarken yeni bir nesneyi işaret edecek şekilde değiştirebileceğiniz gösterilmiştir :

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

2
gerçekten harika bir açıklama! Harita, ... için diğer yineleme yöntemlerinde açıklamayı genişletmek daha da iyi olurdu ... ... için yeni ... işlerin forEach'tan çok benzer bir şekilde olması dışında, " index ", sonunda orijinal diziyi değiştirmek için eksiktir (forEach'ta olduğu gibi). Ayrıca ES5 haritası forEach'a benziyor, belki de bir haritadan değer döndürme olasılığı, sözdizimi perspektifinden indeksi kullanmaktan daha net hale getiriyor.
Christophe Vidal

1
Harika bir açıklama. Teşekkür ederim. Sonuçta bu ifadeyi alamıyorum: In functions, parameters are always passed by value. Ya ikinci örnek?
Alex

@ 7sides, Bu ifade, işlev parametrelerinin her zaman değere göre geçirileceğini açıklar. Yani ilkeller için, ilkelin işaret ettiği değer olacaktır. Nesneler için, nesnenin işaret ettiği konum olacaktır. Bu w3schools sayfasının iyi bir açıklaması var. Bkz. Bağımsız Değişkenler Değerden Geçirilir ve Nesneler Başvurudan Geçirilir .
Dave

Fonksiyonlarda, parametreler her zaman değere göre iletilir. BAM. Teşekkürler. +1
radarbob

92

Dizi: [1, 2, 3, 4]
Sonuç:["foo1", "foo2", "foo3", "foo4"]

Array.prototype.map() Orijinal diziyi koru

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() Orijinal diziyi geçersiz kıl

const originalArr = ["Iron", "Super", "Ant", "Aqua"];
originalArr.forEach((name, index) => originalArr[index] = `${name}man`);

console.log( "Overridden: %s", originalArr );


3
"Array.prototype.map () arr değişkenini yeniden atayarak elde edilen orijinal diziyi değiştir" .map () hiçbir zaman orijinal diziyi değiştirmez, yeni bir diziyi oluşturur. Değişkenin yeniden atanması orijinal nesneyi değiştirmez.
vadkou

1
let arr1 = ["1", 2, 3, 4]; arr1.map(function(v) { return "foo"+ v; }); console.log( arr ); Array.prototype.map () Asla orijinal diziyi değiştirmeyin, forEach mutate.
Anupam Maurya

@AnupamMaurya Bu hiç doğru değil. mapdizisini kesinlikle değiştirebilir ve forEachgenel olarak değiştirmez .
user4642212

@SebastianSimon, cevap için teşekkürler. Eklemek istediğim tek şey, forEach verileri geçersiz kılar, ancak bir harita, yeni bir kopya oluşturur.
Anupam Maurya

14

Javascript, değere göre geçiştir ve esasen dizideki değerin partbir kopyası anlamına gelir .

Değeri değiştirmek için, döngünüzdeki dizinin kendisine erişin.

arr[index] = 'new value';


Bu part, kopyalanıp kopyalanmamasına bağlıdır - değişkenin bir işaretçi değil, bir değer olduğu konusunda haklı olmanıza rağmen
Bergi

8
"JavaScript değere göre geçer" demek, genel bir genellemedir. JavaScript'te referans türleri vardır. Değer türleri değere göre geçirilir.
Alex Turpin

9
Kaba bir genelleme değil. Tamamen doğru ve mutlak bir ifade. Javascript referansları değere göre geçirir. Javascript her zaman değere göre geçer.
hvgotcodes

1
@Bergi: Hayır, türü önemli değil. Tüm değerler atamada kopyalanır - JavaScript'teki tek değerler ilkel ve referanslardır. Hem temel öğeler hem de referanslar ödevde kopyalanır.
newacct

6
@Bergi, bir dilin referans denilen bir şeyi olması nedeniyle, referansla geçiş kullandığı anlamına gelmez. Referanslar değere göre geçirilebilir (ve geçirilebilir), yani referansın değeri kopyalanır ve bu kopya argüman olarak kullanılır.
hvgotcodes

4

dizinin dizini ile değiştirin.

array[index] = new_value;

2
Harika ... Her zaman bir açıklama ekleyin
devpro

4

İşte bir =>stil fonksiyonu kullanarak benzer bir cevap :

var data = [1,2,3,4];
data.forEach( (item, i, self) => self[i] = item + 10 );

sonucu verir:

[11,12,13,14]

selfParametre yüzden, ok tarzı fonksiyonu ile kesinlikle gerekli değildir

data.forEach( (item,i) => data[i] = item + 10);

ayrıca çalışır.


3

.ForEach işlevi bir geri arama işlevine (eachelement, elementIndex) sahip olabilir. Temel olarak yapmanız gereken şey:

arr.forEach(function(element,index){
    arr[index] = "four";   //set the value  
});
console.log(arr); //the array has been overwritten.

Veya orijinal diziyi saklamak istiyorsanız, yukarıdaki işlemi yapmadan önce dizinin bir kopyasını oluşturabilirsiniz. Bir kopya oluşturmak için şunları kullanabilirsiniz:

var copy = arr.slice();

3
Dizinin bir kopyasını oluşturmak istiyorsanız, map()yerine kullanın forEach(). map()kaynak dizi üzerinden yinelenir ve orijinalin [değiştirilmiş] kopyasını içeren yeni bir dizi döndürür: kaynak dizi değişmeden kalır.
Nicholas Carey

2

Array nesnesi yöntemleriyle, Array içeriğini döngülerin temeline kıyasla henüz değiştirebilirsiniz, bu yöntemlerde önemli bir işlevsellik yoktur. Çalışma sırasında dizini değiştiremezsiniz.

Örneğin, geçerli öğeyi kaldırır ve aynı dizi içindeki başka bir dizin konumuna yerleştirirseniz, bunu kolayca yapabilirsiniz. Geçerli öğeyi önceki bir konuma taşırsanız, bir sonraki yinelemede sorun olmazsa, bir şey yapmamışsınız gibi bir sonraki öğeyi alırsınız.

İndeks 5'e kadar sayıldığında, indeks konumu 5'teki öğeyi indeks konumu 2'ye taşıdığımız bu kodu düşünün.

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

Ancak, geçerli öğeyi geçerli dizin konumunun ötesinde bir yere taşırsak, işler biraz dağınık hale gelir. Ardından, sonraki öğe taşınan öğeler konumuna geçer ve sonraki yinelemede onu göremez veya değerlendiremeyiz.

İndeks 5'e kadar sayıldığında, indeks pozisyonu 5'teki öğeyi indeks pozisyonu 7'ye taşıdığımız bu kodu düşünün.

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

Bu yüzden döngüde 6 ile hiç tanışmadık. Normalde for döngüsünde, dizi öğesini ileri taşıdığınızda dizin değerini azaltmanız beklenir, böylece dizininiz bir sonraki çalıştırmada aynı konumda kalır ve kaldırılan öğenin yerine kaydırılan öğeyi yine de değerlendirebilirsiniz. Dizi yöntemleri ile bu mümkün değildir. Dizini değiştiremezsiniz. Aşağıdaki kodu kontrol edin

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

Ne zaman azaldığımızı gördüğünüz gibi i, 5'ten 6'ya, kaldığı yerden devam etmeyecek.

Bunu aklınızda bulundurun.


1

Tamamen dizini değiştirecek öğeler eklemek veya silmek için, zhujy_8833 dilim () önerisini bir kopya üzerinde yinelemek üzere genişleterek, sildiğiniz veya eklediğiniz öğelerin sayısını sayın ve dizini buna göre değiştirin. Örneğin, öğeleri silmek için:

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

Önceden eleman eklemek için:

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

Sonrasında öğeler eklemek için:

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

Bir öğeyi değiştirmek için:

if (value === "A3" || value === "A4" || value === "A7") {
    values.splice(index, 1, 'newVal');
};

// Expected: [ 'A0', 'A1', 'A2', 'newVal', 'newVal', 'A5', 'A6', 'newVal', 'A8' ]

Not: Hem 'önce' hem de 'sonra' ekleri uygularsanız, kod önce 'ekler' önce eklenmelidir, aksi takdirde beklendiği gibi olmaz


0

Geçersiz kılmak istiyorsanız bunu deneyebilirsiniz

var newArray= [444,555,666];
var oldArray =[11,22,33];
oldArray.forEach((name, index) => oldArray [index] = newArray[index]);
console.log(newArray);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.