当前位置:网站首页>Have you learned the wrong usage of foreach
Have you learned the wrong usage of foreach
2022-07-02 14:56:00 【Front end technology station】

Programmer's interview question bank web Front end interview question bank VS java Back end interview question bank
Preface
Have used forEach There are roughly two kinds of people : Common use , A simple ; Complex use , I always want to make some tricks , The result is some inexplicable bug And that's what happened , Solve these bug The time spent can be realized in a different way , Can be used as for Cyclic , It's not just forEach. you 're right , The author is the latter , After all, it's me “ Poor learning ”. So , Take some time. , Combined with our own practical development experience , Let's take care of it forEach.
grammar
forEach() Is a prototype method of an array object , This method will execute the given callback function once for each element in the array , also Always return undefined. Class array objects are not forEach Methodical , for example arguments.forEach It's easy to use :
arr.forEach(callback(currentValue [, index [, array]])[, thisArg]) Practical example :
const arr = [1,2,3];
arr.forEach(item => console.log(item)); // 1,2,3 Parameter description :
callback: The callback function to be executed by each element in the array , There can be 1-3 Parameters
currentValue: Elements currently being processed , Will passindex: Index of the element currently being processed , Optional parametersarray:forEach Method to manipulate the original array object , Optional parameters
thisArg: Current implementation callback When calling back a function , Of the callback function this Point to , The global object that is pointed to by default , Optional parameters
The grammar doesn't seem complicated , So let's see if we can make the following mistakes :
Incorrect usage
Incorrect usage refers to the operation described by the title , Not the body content , Bear in mind , Bear in mind .
Programmer's interview question bank web Front end interview question bank VS java Back end interview question bank

Add or delete data in the original array
forEach() stay for the first time call callback Will determine the traversal range , Generally speaking, it will be in ascending order according to the index Valid elements Do it once callback function . If it is an uninitialized array item or is calling forEach() Items added to the array are not accessed , If the elements in the array are deleted during traversal , Unexpected situations may occur .
Invalid values will be skipped directly
Add element after call , Will not be accessed
const arr = [1,,,2,4];console.log(arr.length); // 5let callbackCounts = 0;
arr.forEach(item => {
console.log(item); // 1 2 4
callbackCounts++;
arr.push(6); // Add element after call , Will not be accessed })console.log(callbackCounts); // 3console.log(arr); // [1,,,2,4,6,6,6] Delete the elements in the array
const arr = ['a', 'b', 'c', 'd'];console.log(arr.length); // 4let callbackCounts = 0;
arr.forEach((item, index) => { // arr.shift();
console.log(item); // 'a','b','d', among 'c' Will be skipped
if (item === 'b') {
// arr.shift(); // Delete the head ,arr Result :['b', 'c', 'd']
arr.splice(index, 1); // Delete current element ,arr Result :['a', 'c', 'd']
// arr.splice(-1); // Delete the last element ,arr Result :['a', 'b', 'c']
}
callbackCounts++;
})console.log(callbackCounts); // 3console.log(arr); // ['a', 'c', 'd']Deleting elements can be a bit more complicated , Interested friends can test by themselves , We can understand that :
forEach The traversal range is determined at the time of the call , Pass to callback The value of is forEach The value when traversing the element , Even in callback The element in the array is deleted in , But the value has been passed in
If it is a valid value ,callbackCounts It will increase . At the next cycle ,forEach The corresponding value of the current cycle will be obtained according to the index of the previous cycle , Notice that the array length has changed at this time , Will appear “ skip ” The phenomenon of
Then repeat , Know that the array traversal is completed
Got it ” skip “, How dare you take it for granted to delete the data in the array ?
Modify the data in the original array
Since you can't add or delete , What if I revise it ? Actually, modify the elements in the array , No, no, no , Just pay attention to the method of use .
If the array contains basic data types :string、number、boolean etc. , Only using the first parameter of the callback function to modify the value in the array will not affect the original array
const arr = [1,2,3,4,5] arr.forEach((item, index, array) => { item+=1; // [1,2,3,4,5] // arr[index]+=1; // [2,3,4,5,6] // array[index]+=1; // [2,3,4,5,6]})console.log(arr);If the in the array is a reference data type :object etc. , Replacing array items directly will not affect the original array
const arr = [ {name: ' Zhang San ', id: 1}, {name: ' Li Si ', id: 2} ] arr.forEach((item, index, array) => { if (item.id === 2) { item = {name: ' Wang Wu ', id: item.id}; // Zhang San 、 Li Si // Object.assign(item, {name: ' Wang Wu ', id: item.id}); // Zhang San 、 Wang Wu // arr[index] = {name: ' Wang Wu ', id: item.id}; // Zhang San 、 Wang Wu // array[index] = {name: ' Wang Wu ', id: item.id}; // Zhang San 、 Wang Wu } })console.log(arr);When the array object is traversed , In fact, the array items are Refer to the address Assign a value to
item, If you reassign the reference address of another object toitem, It does not change the data of the original reference address , It will not affect the original array .If the in the array is a reference data type :object etc. , At this point, we only modify a certain attribute of the array item , At this time, the original array will be affected
const arr = [ {name: ' Zhang San ', id: 1}, {name: ' Li Si ', id: 2} ] arr.forEach((item, index, array) => {if (item.id === 2) { item.name = ' Wang Wu '; // arr[index].name = ' Wang Wu '; // Zhang San 、 Wang Wu // array[index].name = ' Wang Wu '; // Zhang San 、 Wang Wu } })console.log(arr); // Zhang San 、 Wang WuThe truth is the same as 2 similar ,
itemIt points to the reference address , Modifying the attribute is equivalent to modifying the attribute of the object in the reference address , The original array will also be modified
To sum up, we can find , If you want to in forEach Modify the original array , Then you need to use the callback function , Through the index index Or with the help of Object.assgin() To achieve , The final principle is to modify the data in the reference address , Instead of directly modifying .
Asynchronous functions are used in callback functions
The execution order of asynchronous functions and synchronous functions will not be discussed in detail here , Details can be moved : Don't understand the event cycle , Take a look at this article , Simply put, synchronous code executes before asynchronous code .
Take an example :
const arr = [1,2,3,4,5]let sum = 0;let callbackCounts = 0;function Sum(a, b) {
return new Promise((resovle) => {
resovle(a + b)
})
}
arr.forEach(async (item, index, array) => {
sum = await Sum(sum, item)
})console.log(sum); // 0The actual value of the sum is not what we expect 15, It is 0.
If we need to implement asynchronous summation , have access to for Cycle to achieve :
const arr = [1,2,3,4,5]let sum = 0;let callbackCounts = 0;function Sum(a, b) {
return new Promise((resovle) => {
resovle(a + b)
})
}
(async function() {
for (let item of arr) {
sum = await Sum(sum, item)
}
console.log(sum); // 15})();Use return End of cycle
In the use of for loop , We can generally use break、return To jump out of the loop , Throwing an exception can also , But this is not a normal development process . Let's try it in forEach Use in break、return Does it work :
forEach End of cycle
const arr = [1,2,3,4,5]let callbackCounts = 0;
arr.forEach((item, index, array) => {
callbackCounts++;
if (item === 2) {
return; // forEach Cannot be used in break, Even using return, Nor can you stop the loop
}
})console.log(arr.length, callbackCounts); // 5 5 If you have to jump out forEach loop , The first suggestion is to use other looping methods , for example :for、for of、for in、map etc. , Second, we can consider throwing an exception to jump out forEach loop :
const arr = [1,2,3,4,5]let callbackCounts = 0;try {
arr.forEach((item, index, array) => {
callbackCounts++;
if (item === 2) {
throw 'throw forEach';
}
})
} catch (e) { console.log(arr.length, callbackCounts); // 5 2} If you really want to use throw To throw an exception , Isn't it nice to use other recycling methods
No incoming this
forEach() There may be this Point to the problem , for example :
function Counter() {
this.sum = 0;
}
Counter.prototype.add = function (array) {
array.forEach(function(element) {
this.sum += element;
});
}const obj = new Counter();
obj.add([1,2,3,4,5])console.log(obj.sum); // 0 Not specified this, The default is not window object , At this time this.sum by undefined, And what we think is this Point to the passed in array . Then you need to pass in this Or use the arrow function .
array.forEach((element) => { this.sum += element;
});
array.forEach(function(element) { this.sum += element;
}, this);Proper use
Avoid incorrect usage , Of course, it is the correct usage .
Actually forEach It was designed just to simplify for Loop traversal , If there are too many other operations , It goes against the original intention of the design . every last API They all have their own scope of application , If you insist on a shuttle , May step on a lot of holes .
A brief summary of the correct use :
It's best to just iterate through the original array , It does not involve modifying the data in the original array
Avoid asynchronous operations in callback functions
Out of commission return
forEach()The callback function of uses the arrow function , Avoidable this Point to the problem
summary
forEachItself does not change the original array , But its callback function may be modified . If you really want to modify the original array , It is recommended to usemap、filterOther methodsforEachMethod always returns undefined, This makesforEachNot likemap、filterYou can also chain callIn addition to throwing an exception ,
forEachCannot be aborted or jump out of the loop , If you want to jump out of the loop , It is recommended to use other methods for Cycle methodIf asynchronous functions are involved , Consider using
for await ofInstead offorEach
Programmer's interview question bank web Front end interview question bank VS java Back end interview question bank

边栏推荐
- Li Chuang EDA learning notes 15: draw border or import border (DXF file)
- 华为面试题: 没有回文串
- Add vector formula in rich text editor (MathType for TinyMCE, visual addition)
- buuctf-pwn write-ups (7)
- Yyds dry goods inventory software encryption lock function
- 实现一个多进程并发的服务器
- taobao.logistics.dummy.send( 无需物流发货处理 )接口,淘宝店铺发货API接口,淘宝订单发货接口,淘宝r2接口,淘宝oAu2.0接口
- It's no exaggeration to say that this is the most user-friendly basic tutorial of pytest I've ever seen
- Fabric.js 手动加粗文本iText
- Database connection pool and data source
猜你喜欢

大顶堆、小顶堆与堆排序

Yyds dry goods inventory software encryption lock function

报错:npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.

kityformula-editor 配置字号和间距

【空间&单细胞组学】第1期:单细胞结合空间转录组研究PDAC肿瘤微环境

obsidian安装第三方插件——无法加载插件

Fundamentals of software testing

一张图彻底掌握prototype、__proto__、constructor之前的关系(JS原型、原型链)

STM32库函数进行GPIO初始化

Obsidian installs third-party plug-ins - unable to load plug-ins
随机推荐
Yyds dry goods inventory software encryption lock function
Actual combat sharing of shutter screen acquisition
用户隐私协议有些汉字编码不规范导致网页显示乱码,需要统一找出来处理一下
记一次报错解决经历依赖重复
Tmall product details interface (APP, H5 end)
[development environment] StarUML tool (download software | StarUML installation | StarUML creation project)
Tujia muniao meituan has a discount match in summer. Will it be fragrant if the threshold is low?
Fabric. JS free drawing ellipse
geoserver离线地图服务搭建和图层发布
Fabric. JS dynamically set font size
MFC A对话框调用B对话框函数并传参
LeetCode 2310. The number of digits is the sum of integers of K
Fabric.js 元素被选中时保持原有层级
About text selection in web pages and counting the length of selected text
fatal: unsafe repository is owned by someone else 的解决方法
It's no exaggeration to say that this is the most user-friendly basic tutorial of pytest I've ever seen
taobao. logistics. dummy. Send (no logistics delivery processing) interface, Taobao store delivery API interface, Taobao order delivery interface, Taobao R2 interface, Taobao oau2.0 interface
NLA natural language analysis makes data analysis more intelligent
[QNX hypervisor 2.2 user manual]6.3 communication between guest and external
fatal: unsafe repository is owned by someone else 的解决方法