предговор
Честно казано, не обичам да използвам forEach, защото някои от грешките, които причинява, винаги са толкова непреднамерени, прегледайте причините, които не ми харесват.
Причина 1: не поддържа обработка на асинхронни функции
Нека първо да разгледаме един пример:
async function test() { let arr = [3, 2, 1] arr.forEach(async item => { const res = await mockSync(item) console. log(res) }) console. log('end') } function mockSync(x) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(x) }, 1000 * x) }) } test() The result we expect is: 3 2 1 end but actually outputs: end 1 2 3
JavaScript
Методът в forEach()
е синхронен метод, който не поддържа работа с асинхронни функции. Ако forEach
изпълните асинхронна функция в , forEach()
тя не може да изчака асинхронната функция да завърши, тя ще продължи да изпълнява следващия елемент. forEach()
Това означава, че няма гаранция за реда, в който ще се изпълняват асинхронни задачи, ако в тях се използва асинхронна функция.
алтернативен forEach
way
1. Метод 1
Можете да използвате напр. map()
, filter()
, reduce()
и т.н. които поддържат връщане във функциите Promise
и ще чакат всички обещания да бъдат изпълнени.
Примерният код за използване на map()
и Promise.all()
за обработка на асинхронни функции е както следва:
const arr = [1, 2, 3, 4, 5]; async function asyncFunction(num) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(num * 2); }, 1000); }); } const promises = arr.map(async (num) => { const result = await asyncFunction(num); return result; }); Promise.all(promises).then((results) => { console.log(results); // [2, 4, 6, 8, 10] });
Тъй като използвахме await
ключовата дума в async функцията, map()
методът изчаква async функцията да завърши и връща резултата, така че да можем да обработваме async функцията правилно.
2. Метод 2
използва for цикъл за обработка на асинхронни функции
const arr = [1, 2, 3, 4, 5]; async function asyncFunction(num) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(num * 2); }, 1000); }); } async function processArray() { const results = []; for (let i = 0; i < arr.length; i++) { const result = await asyncFunction(arr[i]); results.push(result); } console.log(results); // [2, 4, 6, 8, 10] } processArray();
Причина 2: Не могат да се уловят грешки в асинхронните функции
Ако асинхронна функция хвърля грешка по време на изпълнение, forEach()
няма начин да се хване тази грешка. Това означава, че дори ако възникне грешка в асинхронна функция, forEach()
execution ще продължи.
Причина 3: Няма начин да прекъснете или излезете от цикъла, освен да хвърлите изключение
forEach()
Method не поддържа използването на израза break
или continue
за излизане от цикъл или за пропускане на елемент. Ако трябва да излезете от цикъл или да пропуснете елемент, трябва да използвате for
цикъл или друг метод за поддържане break
или continue
изявление.
Причина 4: forEach изтрива собствените си елементи, индексът не може да бъде нулиран
Не можем да контролираме стойността на индекса в forEach
, тя ще се увеличава автоматично само докато стане по-голяма от дължината на масива и ще излезе от цикъла. Следователно е невъзможно да се изтрие, за да нулира индекса. Нека да разгледаме един прост пример:
let arr = [1,2,3,4] arr.forEach((item, index) => { console.log(item); // 1 2 3 4 index++; });
Причина 5: това сочи към проблема
В рамките на forEach()
a метод, this
ключовата дума се отнася до обекта, на който се извиква методът. this
Въпреки това, обхватът на ключова дума може да бъде проблематичен, когато се използват нормални функции или функции със стрелки като аргументи. Във функция със стрелка ключовата дума this се отнася до обекта, в който е дефинирана функцията. В нормална функция ключовата дума this се отнася до обекта, който е извикал функцията. Ако трябва да се уверите, че обхватът на ключовата дума this е правилен, можете да използвате метода bind(), за да обвържете обхвата на функцията. Ето пример за проблем с обхвата на ключова дума forEach()
в метод this
:
const obj = { name: "Alice", friends: ["Bob", "Charlie", "Dave"], printFriends: function () { this.friends.forEach(function (friend) { console.log(this.name + " is friends with " + friend); }); }, }; obj.printFriends();
В този пример ние дефинираме obj
обект с име, който има printFriends()
method. В printFriends()
метода, ние използваме forEach()
метода за итерация върху friends
масива и използваме нормалната функция, за да отпечатаме името на всеки приятел и свойствата obj
на обекта name
. Въпреки това, когато стартираме този код, изходът е:
undefined is friends with Bob undefined is friends with Charlie undefined is friends with Dave
Това е така, защото forEach()
когато нормална функция се използва в метод, обхватът на функцията не е printFriends()
обектът, извикващ метода, а глобалният обхват. Следователно свойствата на обекта не могат да бъдат достъпни в рамките на тази функция obj
.
За да заобиколите това, можете да използвате bind()
methods за обвързване на обхвата на функцията или да използвате функции със стрелки, за да дефинирате функции за обратно извикване. Ето bind()
пример на код, който използва метод за решаване на проблема:
const obj = { name: "Alice", friends: ["Bob", "Charlie", "Dave"], printFriends: function () { this.friends.forEach( function (friend) { console.log(this.name + " is friends with " + friend); }.bind(this) // Use the bind() method to bind the scope of the function ); }, }; obj. printFriends();
В този пример използваме bind()
methods, за да обвържем обхвата на функцията, който обвързва обхвата на функцията с obj
обекта. След изпълнение на кода изходът е:
Alice is friends with Bob Alice is friends with Charlie Alice is friends with Dave
Като използваме bind()
methods за обвързване на обхвата на функцията, можем да осъществим правилен достъп до obj
свойствата на обекта.
Друго решение е да използвате функции със стрелки. Тъй като функцията стрелка няма свой собствен this
, тя наследява от обхвата, който е в this
. И така, във функция със стрелка this
ключовата дума се отнася до обекта, в който е дефинирана функцията. кодово съкращение.
Причина 6: Производителността на forEach е по-ниска от тази на цикъла for
for
: Цикълът for няма допълнителен стек за извикване на функция и контекст, така че внедряването му е най-просто.forEach
: Сигнатурата на ForEach съдържа параметри и контекст, така че производителността ще бъде по-ниска от for
цикъла.
Причина 7: Изтрити или неинициализирани елементи ще бъдат пропуснати
// skip uninitialized values const array = [1, 2, /* empty */, 4]; let num = 0; array. forEach((ele) => { console. log(ele); num++; }); console.log("num:",num); // 1 // 2 // 4 // num: 3 // skip deleted values const words = ['one', 'two', 'three', 'four']; words. forEach((word) => { console. log(word); if (word === 'two') { // When the item containing the value `two` is reached, the first item of the entire array is removed // This causes all remaining items to be moved up one position. Since the element `four` is at the beginning of the array, `three` is skipped. words.shift(); //'one' will be removed from the array } }); // one // two // four console.log(words); // ['two', 'three', 'four']
Причина 8: използването на forEach няма да промени оригиналния масив
forEach()
Когато бъде извикан, оригиналният масив, т.е. масивът, който го е извикал, няма да бъде променен. Но този обект може да бъде променен от предадената функция за обратно извикване.
// example one const array = [1, 2, 3, 4]; array.forEach(ele => { ele = ele * 3 }) console.log(array); // [1,2,3,4] // Solution, change the original array const numArr = [33,4,55]; numArr.forEach((ele, index, arr) => { if (ele === 33) { arr[index] = 999 } }) console.log(numArr); // [999, 4, 55] // Example 2 const changeItemArr = [{ name: 'wxw', age: 22 }, { name: 'wxw2', age: 33 }] changeItemArr.forEach(ele => { if (ele.name === 'wxw2') { ele = { name: 'change', age: 77 } } }) console.log(changeItemArr); // [{name: "wxw", age: 22},{name: "wxw2", age: 33}] // solution const allChangeArr = [{ name: 'wxw', age: 22}, { name: 'wxw2', age: 33}] allChangeArr.forEach((ele, index, arr) => { if (ele.name === 'wxw2') { arr[index] = { name: 'change', age: 77 } } }) console.log(allChangeArr); // // [{name: "wxw", age: 22},{name: "change", age: 77}] copy code
Е, ще го използвам for...of
вместоforEach