javascript - لكل من خلال مجموعة في جافا سكريبت؟




14 Answers

تحرير : هذه الإجابة قديمة بشكل يائس. للحصول على نهج أكثر حداثة ، انظر إلى الطرق المتاحة على صفيف . طرق الاهتمام قد تكون:

  • forEach
  • خريطة
  • منقي
  • الرمز البريدي
  • خفض
  • كل
  • بعض

الطريقة القياسية لتكرار صفيف في JavaScript هو الفانيلا من for :

var length = arr.length,
    element = null;
for (var i = 0; i < length; i++) {
  element = arr[i];
  // Do something with element
}

ومع ذلك ، لاحظ أن هذا الأسلوب جيد فقط إذا كان لديك صفيف كثيف ، وكل عامل مشغول بواسطة عنصر. إذا كانت الصفيف متفرقة ، فيمكنك عندئذ تشغيل مشاكل الأداء مع هذا الأسلوب ، حيث ستتكشف على الكثير من المؤشرات التي لا توجد بالفعل في الصفيف. في هذه الحالة ، قد يكون for .. in -loop فكرة أفضل. ومع ذلك ، يجب عليك استخدام الضمانات المناسبة للتأكد من أن الخصائص المرغوبة للمصفوفة (أي ، عناصر الصفيف) يتم التصرف عليها ، حيث سيتم أيضًا تعداد for..in -loop في المتصفحات القديمة ، أو إذا كانت يتم تعريف خصائص كما enumerable .

في ECMAScript 5 سيكون هناك أسلوب forEach في النموذج الأولي للمصفوفة ، ولكنه غير مدعوم في المتصفحات القديمة. حتى تكون قادرًا على استخدامه باستمرار ، يجب أن يكون لديك بيئة تدعمه (على سبيل المثال ، Node.js لجافا سكريبت من جانب الخادم) ، أو استخدام "Polyfill". ومع ذلك ، فإن Polyfill لهذه الوظيفة بسيط ، ولأنه يسهل قراءة الكود ، فإنه يعتبر تهيئته جيدًا لتضمينه.

javascript arrays loops foreach iteration

كيف يمكنني تكرار جميع الإدخالات في صفيف باستخدام JavaScript؟

اعتقدت انه شيء من هذا القبيل:

forEach(instance in theArray)

أين هو theArray ، ولكن يبدو أن هذا غير صحيح.




عروة للخلف

أعتقد أن العكس للحلقة يستحق الذكر هنا:

for (var i = array.length; i--; ) {
     // process array[i]
}

مزايا:

  • لا تحتاج إلى إعلان متغير len مؤقت ، أو مقارنة ضد array.length في كل تكرار ، قد يكون أي منهما array.length .
  • إزالة الأشقاء من DOM بترتيب عكسي عادة ما تكون أكثر كفاءة . (يحتاج المتصفح إلى تقليل نقل العناصر في صفائفه الداخلية.)
  • إذا قمت بتعديل المصفوفة أثناء التكرار ، أو عند الفهرس i (على سبيل المثال قمت بإزالة عنصر أو إدراجه في array[i] ) ، فستتخطى حلقة أمامية العنصر الذي تحول إلى اليسار في الموضع i ، أو تعيد معالجة i. البند عشر الذي تم نقله الحق. في حلقة تقليدية ، يمكنك تحديث i للإشارة إلى العنصر التالي الذي يحتاج إلى معالجة - 1 ، ولكن ببساطة عكس اتجاه التكرار هو غالباً حل أبسط وأنيق .
  • وبالمثل ، عند تعديل عناصر DOM المتداخلة أو إزالتها ، يمكن للمعالجة في الاتجاه المعاكس التحايل على الأخطاء . على سبيل المثال ، فكر في تعديل innerHTML لعقدة رئيسية قبل التعامل مع الأطفال. في الوقت الذي يتم فيه الوصول إلى العقدة الفرعية ، سيتم فصله عن DOM ، بعد أن تم استبداله بطفل تم إنشاؤه حديثًا عندما تم كتابة لغة HTML الداخلية.
  • من الأقصر الكتابة والقراءة أكثر من بعض الخيارات الأخرى المتاحة. على الرغم من أنه يخسر ل forEach() و ES6 ل for ... of .

سلبيات:

  • يقوم بمعالجة العناصر بترتيب عكسي. إذا كنت تقوم ببناء مصفوفة جديدة من النتائج ، أو طباعة أشياء على الشاشة ، فسيتم عكس الناتج بشكل طبيعي فيما يتعلق بالترتيب الأصلي.
  • يعد إدراج الأشقاء بشكل متكرر في DOM كطفل أول من أجل الاحتفاظ بأمرهم أقل كفاءة . (سيبقى المتصفح مضطرًا إلى تغيير الأمور بشكل صحيح.) لإنشاء عقد DOM بطريقة فعّالة وفي ترتيب ، ما عليك سوى إعادة توجيه الزوايا وإلحاقها كالمعتاد (وأيضًا استخدام "جزء المستند").
  • حلقة عكسي مربكة للمطورين المبتدئين. (قد تفكر في هذه الميزة ، اعتمادا على نظرتك.)

هل يجب علي دائمًا استخدامها؟

يستخدم بعض المطورين العكسي للحلقة افتراضيًا ، ما لم يكن هناك سبب وجيه لإجراء تكرار للأمام.

على الرغم من أن مكاسب الأداء عادةً ما تكون غير ذات أهمية ، إلا أنها نوع من الصراخ:

"فقط افعل ذلك لكل عنصر في القائمة ، لا يهمني الأمر!"

ومع ذلك ، لا يعد ذلك في الواقع إشارة موثوقة على النية ، نظرًا لأنه لا يمكن تمييزه عن تلك المناسبات عندما تهتم بالأمر ، وتحتاج حقًا إلى الرجوع إلى الخلف. في الواقع ، ستكون هناك حاجة لبنية أخرى للتعبير بدقة عن نية "لا يهمني" ، وهو أمر غير متوفر حاليًا في معظم اللغات ، بما في ذلك ECMAScript ، ولكن يمكن استدعاؤه ، على سبيل المثال ، forEachUnordered() .

إذا لم يكن الأمر مهمًا ، وكانت الكفاءة مصدر قلق (في الحلقة الداخلية لمحرك ألعاب أو حركة متحركة) ، فقد يكون من المقبول استخدام الرجوع للخلف كنمط الانتقال. فقط تذكر أن رؤية عكس للحلقة في الكود الحالي لا يعني بالضرورة أن الأمر غير ذي صلة!

من الأفضل استخدام forEach ()

بوجه عام ، بالنسبة إلى الشفرة ذات المستوى الأعلى حيث تُعد درجة الوضوح والسلامة من المخاوف الأكبر ، فإنني Array::forEach باستخدام Array::forEach الافتراضي:

  • من الواضح أن تقرأ.
  • يشير هذا إلى أنه لن يتم تحويلي داخل الكتلة (وهو دائمًا ما يمثل مفاجأة محتملة مختبئة في حلقات طويلة while .)
  • يمنحك نطاقًا مجانيًا للإغلاق.
  • فهو يقلل من تسرب المتغيرات المحلية والتصادم العرضي مع المتغيرات الخارجية (والطفرات).

بعد ذلك ، عندما ترى عكس الحل في الشفرة ، فهذا تلميح إلى أنه يتم عكسه لسبب وجيه (ربما أحد الأسباب الموضحة أعلاه). ورؤية التتابع التقليدي للحلقة قد يشير إلى أن التحول قد يحدث.

(إذا لم تكن مناقشة النوايا منطقية بالنسبة لك ، فقد تستفيد أنت ورمزك من مشاهدة محاضرة كروكفورد حول أسلوب البرمجة ودماغك .)

كيف يعمل؟

for (var i = 0; i < array.length; i++) { ... }   // Forwards

for (var i = array.length; i--; )    { ... }   // Reverse

ستلاحظ أن i-- هي العبارة المتوسطة (حيث نرى عادة المقارنة) وأن الجملة الأخيرة فارغة (حيث نرى عادة i++ ). وهذا يعني أن i-- تستخدم أيضًا كشرط للاستمرار. بشكل حاسم ، يتم تنفيذه وفحصه قبل كل تكرار.

  • كيف يمكن أن تبدأ في array.length دون انفجار؟

    نظرًا لأن i-- يعمل قبل كل عملية تكرار ، ففي أول عملية تكرار ، سنتمكن بالفعل من الوصول إلى العنصر في array.length - 1 الذي يتجنب أي مشكلات تتعلق array.length - 1 خارج النطاق undefined .

  • لماذا لا يتوقف عن التكرار قبل الفهرس 0؟

    ستتوقف الحلقة عن التكرار عند تقييم الحالة i-- إلى قيمة falsey (عندما تعطي 0).

    الخدعة هي أنه على عكس - --i ، يتتبع مشغل i trailing i ولكنه يعطي القيمة قبل الانخفاض. يمكن أن توضح وحدة التحكم الخاصة بك هذا:

    > var i = 5; [i, i--, i];

    [5, 5, 4]

    إذن في التكرار النهائي ، كنت في السابق 1 والتعبير i-- يغيره إلى 0 ولكنه في الواقع ينتج 1 (صحيح) ، وهكذا تمر الحالة. في التكرار التالي i - يتغير i إلى -1 ولكن ينتج 0 (falsey) ، مما يؤدي إلى تنفيذ التنفيذ على الفور من أسفل الحلقة.

    في العقود التقليدية للحلقة ، i++ و ++i قابلة للتبادل (كما يشير دوغلاس كروكفورد). ولكن في الاتجاه المعاكس للحلقة ، لأن تناقصنا هو أيضًا تعبير الحالة الخاص بنا ، يجب علينا الالتزام بـ i-- إذا أردنا معالجة العنصر في index 0.

توافه

يحب بعض الأشخاص رسم سهم صغير في الاتجاه المعاكس للحلقة ، وينتهي بغمزة:

for (var i = array.length; i --> 0 ;) {

تذهب الاعتمادات إلى WYL لتعرض لي فوائد وأهوال العكس للحلقة.




إذا كنت تريد التكرار عبر صفيف ، استخدم الحلقة القياسية الثلاثية الأجزاء.

for (var i = 0; i < myArray.length; i++) {
    var arrayItem = myArray[i];
}

يمكنك الحصول على بعض تحسينات الأداء من خلال التخزين المؤقت myArray.length أو التكرار فوقه إلى الخلف.




إذا كنت لا تمانع في إفراغ الصفيف:

var x;

while(x = y.pop()){ 

    alert(x); //do something 

}

xسيحتوي على القيمة الأخيرة yوسيتم إزالته من المصفوفة. يمكنك أيضًا استخدام shift()الذي سيعطي العنصر الأول وإزالته منه y.




الحل السهل الآن هو استخدام مكتبة underscore.js . إنه يوفر العديد من الأدوات المفيدة ، مثل eachسيقوم تلقائيًا بتفويض المهمة إلى السكان الأصليين forEachإذا كانت متوفرة.

مثال CodePen عن كيفية عمله هو:

var arr = ["elemA", "elemB", "elemC"];
_.each(arr, function(elem, index, ar)
{
...
});

أنظر أيضا

  • Array::forEach .
  • في for_each...in (MDN) ، يتم شرح ذلك بأنه for each (variable in object)تم إيقافه كجزء من معيار ECMA-357 ( EAX ).
  • for...of (MDN) يصف الطريقة التالية لتكرار استخدامه for (variable of object)كجزء من اقتراح Harmony (ECMAScript 6).



هناك ثلاثة تطبيقات foreachفي jQuery النحو التالي.

var a = [3,2];

$(a).each(function(){console.log(this.valueOf())}); //Method 1
$.each(a, function(){console.log(this.valueOf())}); //Method 2
$.each($(a), function(){console.log(this.valueOf())}); //Method 3



لا توجد أي for eachحلقة في JavaScript الأصلي . يمكنك استخدام المكتبات للحصول على هذه الوظيفة (أوصي بـ Underscore.js ) ، استخدم forحلقة بسيطة في حلقة.

for (var instance in objects) {
   ...
}

ومع ذلك ، لاحظ أنه قد تكون هناك أسباب لاستخدام forحلقة أبسط من ذلك (انظر السؤال حول لماذا يستخدم "for… in" مع تكرار الصفات مثل هذه الفكرة السيئة؟ )

var instance;
for (var i=0; i < objects.length; i++) {
    var instance = objects[i];
    ...
}



هناك عدة طرق للتكرار من خلال مصفوفة في جافا سكريبت ، على النحو التالي:

ل- انها الاكثر شيوعا. كتلة كاملة من التعليمات البرمجية لحلقات

var languages = ["JAVA", "JavaScript", "C#", "Python"];
var i, len, text;
for (i = 0, len = languages.length, text = ""; i < len; i++) {
    text += languages[i] + "<br>";
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

بينما - حلقة في حين أن الشرط من خلال. يبدو أن الحلقة الأسرع

var text = "";
var i = 0;
while (i < 10) {
    text +=  i + ") something<br>";
    i++;
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

القيام / أثناء - أيضًا التكرار من خلال كتلة من التعليمات البرمجية أثناء تحقق الشرط ، سيتم تشغيله مرة واحدة على الأقل

var text = ""
var i = 0;
do {
    text += i + ") something <br>";
    i++;
}
while (i < 10);
document.getElementById("example").innerHTML = text;
<p id="example"></p>

الحلقات الوظيفية - forEach، map، filterأيضًا reduce(يتم تكرارها من خلال الدالة ، ولكن يتم استخدامها إذا كنت بحاجة إلى إجراء شيء ما مع الصفيف ، إلخ.

// For example, in this case we loop through the number and double them up using the map function
var numbers = [65, 44, 12, 4];
document.getElementById("example").innerHTML = numbers.map(function(num){return num * 2});
<p id="example"></p>

لمزيد من المعلومات والأمثلة حول البرمجة الوظيفية على المصفوفات ، انظر إلى مشاركة المدونة البرمجة الوظيفية في JavaScript: خريطة وتصفية وتقليل .




ECMAScript5 (الإصدار الموجود على Javascript) للعمل مع صفائف.

forEach - يتكرر من خلال كل عنصر في الصفيف وتفعل كل ما تحتاجه مع كل عنصر.

['C', 'D', 'E'].forEach(function(element, index) {
  console.log(element + " is the #" + (index+1) + " in musical scale");
});

// Output
// C is the #1 in musical scale
// D is the #2 in musical scale
// E is the #3 in musical scale

في حالة ، أكثر اهتماما بالعملية على صفيف باستخدام بعض ميزة يحمل في ثناياه عوامل.

map - يقوم بإنشاء مصفوفة جديدة مع نتيجة وظيفة رد الاتصال. هذه الطريقة جيدة لاستخدامها عندما تحتاج إلى تنسيق عناصر المصفوفة الخاصة بك.

// Let's upper case the items in the array
['bob', 'joe', 'jen'].map(function(elem) {
  return elem.toUpperCase();
});

// Output: ['BOB', 'JOE', 'JEN']

اختزال - كما يقول الاسم ، فإنه يقلل من الصفيف إلى قيمة واحدة عن طريق استدعاء وظيفة معينة تمر في عنصر currenct ونتيجة للتنفيذ السابق.

[1,2,3,4].reduce(function(previous, current) {
  return previous + current;
});
// Output: 10
// 1st iteration: previous=1, current=2 => result=3
// 2nd iteration: previous=3, current=3 => result=6
// 3rd iteration: previous=6, current=4 => result=10

every - إرجاع true أو false إذا اجتازت جميع العناصر في الصفيف الاختبار في وظيفة رد الاتصال.

// Check if everybody has 18 years old of more.
var ages = [30, 43, 18, 5];  
ages.every(function(elem) {  
  return elem >= 18;
});

// Output: false

مرشح - تشبه إلى حد كبير كل ما عدا ذلك المرشح بإرجاع مصفوفة مع العناصر التي ترجع صحتها إلى وظيفة معينة.

// Finding the even numbers
[1,2,3,4,5,6].filter(function(elem){
  return (elem % 2 == 0)
});

// Output: [2,4,6]

اتمني ان يكون ذلك مفيدا.




طريقة jQuery باستخدام $.map:

var data = [1, 2, 3, 4, 5, 6, 7];

var newData = $.map(data, function(element) {
    if (element % 2 == 0) {
        return element;
    }
});

// newData = [2, 4, 6];



لا يعمل بناء الجملة لامدا عادة في IE 10 أو أقل.

أنا عادة ما تستخدم

[].forEach.call(arrayName,function(value,index){
    console.log("value of the looped element" + value);
    console.log("index of the looped element" + index);
});


If you are a jQuery Fan and already have a jQuery file running, you should reverse the positions of the index and value parameters

$("#ul>li").each(function(**index,value**){
    console.log("value of the looped element" + value);
    console.log("index of the looped element" + index);
});



for(let i=0;i<theArray.length;i++){
  console.log(i); //i will have the value of each index
}



إذا كنت ترغب في استخدامها forEach()، سيبدو -

theArray.forEach ( element => { console.log(element); });

إذا كنت ترغب في استخدامها for()، سيبدو -

for(let idx = 0; idx < theArray.length; idx++){ let element = theArray[idx]; console.log(element); }




ملخص:

عند التكرار على صفيف ، غالبًا ما نرغب في تحقيق أحد الأهداف التالية:

  1. نريد التكرار عبر الصفيف وإنشاء مصفوفة جديدة:

    Array.prototype.map

  2. نريد التكرار أكثر من المصفوفة ولا ننشئ مصفوفة جديدة:

    Array.prototype.forEach

    for..of عقدة

في JS هناك العديد من الطرق لتحقيق كل من هذه الأهداف. ومع ذلك ، فإن بعضها أكثر رحابة من غيرها. فيما يلي يمكنك العثور على بعض الطرق الشائعة الاستخدام (أكثر imo conventient) لإنجاز تكرار الصفيف في javascript.

خلق مجموعة جديدة: Map

map()هي وظيفة تقع على Array.prototypeأي منها يمكن تحويل كل عنصر من صفيف ثم إرجاع صفيف جديد . map()يأخذ كحجة وظيفة رد اتصال ويعمل بالطريقة التالية:

let arr = [1, 2, 3, 4, 5];

let newArr = arr.map((element, index, array) => {
  return element * 2;
})

console.log(arr);
console.log(newArr);

يتم تنفيذ رد الاتصال الذي تم تمريره map()إليه كحجة لكل عنصر. ثم يتم إرجاع صفيف له نفس طول الصفيف الأصلي. يتم تحويل عنصر الصفيف الجديد هذا بواسطة وظيفة رد الاتصال التي تم تمريرها كوسيطة لـ map().

الاختلاف المتميز بين mapو آلية الحلقة الأخرى مثل forEachو for..ofالحلقة هي تلك mapالعوائد كمصفوفة جديدة و تترك المجموعة القديمة سليمة (إلا إذا كنت تتعامل مع التفسير مع التفكير splice).

لاحظ أيضًا أن mapمعاودة الاتصال للدالة توفر كوسيطة ثانية رقم الفهرس للتكرار الحالي. علاوة على ذلك ، توفر الوسيطة الثالثة المصفوفة التي mapتم استدعاؤها. في بعض الأحيان يمكن أن تكون هذه الخصائص مفيدة للغاية.

حلقة باستخدام forEach

forEachهي وظيفة تقع على Array.prototypeوالتي تأخذ وظيفة رد اتصال كوسيطة. ومن ثم ينفذ وظيفة رد الاتصال هذه لكل عنصر في الصفيف. على النقيض من map()الوظيفة الدالة forEach بإرجاع لا شيء ( undefined). فمثلا:

let arr = [1, 2, 3, 4, 5];

arr.forEach((element, index, array) => {

  console.log(element * 2);

  if (index === 4) {
    console.log(array)
  }
  // index, and oldArray are provided as 2nd and 3th argument by the callback

})

console.log(arr);

تمامًا مثل mapالدالة ، forEachيوفر رد الاتصال كوسيطة ثانية رقم الفهرس للتكرار الحالي. كما توفر الوسيطة الثالثة المصفوفة التي forEachتم استدعاؤها.

التكرار من خلال العناصر باستخدام for..of

في for..ofحلقة الحلقات من خلال كل عنصر من عناصر مجموعة (أو أي كائن iterable الأخرى). يعمل بالطريقة التالية:

let arr = [1, 2, 3, 4, 5];

for(let element of arr) {
  console.log(element * 2);
}

في المثال أعلاه elementيرمز لعنصر arrالصفيف وهو المصفوفة التي نريد تكرارها. لا يعني أن الاسم elementتعسفي وكان من الممكن أن نختار أي اسم آخر مثل '' el '' أو شيء أكثر إعلانًا عندما يكون ذلك قابلاً للتطبيق.

لا تخلط بين for..inالحلقة for..ofوالحلقة. for..inسوف يتكرر من خلال جميع الخصائص التي لا تعد ولا تحصى من الصفيف ، في حين أن for..ofالحلقة ستعمل فقط على التكرار خلال عناصر الصفيف. فمثلا:

let arr = [1, 2, 3, 4, 5];

arr.foo = 'foo';

for(let element of arr) {
  console.log(element);
}

for(let element in arr) {
  console.log(element);
}






Related