Loops and traversals in JS give us a quick and easy way to do repetitive things. Learning to use different methods in different scenarios helps us write all kinds of code effectively. Here are some common methods, today let us all learn a wave of some.

for

The for loop has three expressions

  1. Declare loop variables
  2. Judgment cycle condition
  3. Update loop variable

Where, three expressions can be omitted, but two; But it cannot be omitted.

let arr = ['a'.'b'.'c']
for(let i = 0; i < arr.length; i++){
    console.log(arr[i])  // a b c
}
Copy the code

We sometimes use a temporary variable to cache the length of the array so we don’t have to fetch it every time we go through the loop

let arr = ['a'.'b'.'c']
for(let i = 0, len = arr.length; i < len; i++){
    console.log(arr[i])  // a b c
}
Copy the code

Writing this in some browsers does provide a performance boost. But in Chrome, which is based on the V8 engine, the performance is basically the same because the browser automatically optimizes it for us at the bottom. Basically, it takes statements that don’t change in the body of the loop and puts them outside the body of the loop. The pseudocode is as follows:

for(let i = 0; i < arr.length; i++){
    total = a + b
    arr[i] = i + total * 2
}
Copy the code

Compile and optimize the above code into the following code:

total = a + b
total2 = total * 2
n = arr.length
for(let i = 0; i < n; i++){
    arr[i] = i + total2
}
Copy the code

So when you’re writing code, it’s up to you whether you want to store variables.

The for loop can loop through strings, arrays, class arrays,DOM nodes, and so on

// Walk through the class array
(function(){
    for(let i=0; i<arguments.length; i++){console.log(arguments[i])  // a b
    }
})('a'.'b')
Copy the code

In addition to the for loop, there are other JS loops, while loop,do-while loop, we will not say.

forEach

Does not change the original array, does not return a new array

let arr = ['a'.'b'.'c']
let arr2 = arr.forEach((item, index, arr) = > {
    return item + '2'
})
console.log(arr)  // ["a", "b", "c"]
console.log(arr2)  // undefined
Copy the code

ForEach can also pass in a second argument to bind the this variable inside the callback function

let arr = ['a'.'b'.'c']
let arr2 = ['d'.'e'.'f']
arr.forEach(function(item, index, arr){
    console.log(this[index])  // d e f
}, arr2)

Copy the code

map

It doesn’t change the original array, it returns the new array

let arr = [2.'a'.'b'.'c'.undefined.null]
let arr2 = arr.map((item, index, arr) = > {
    item = item + '1'
    return item + '2'
})
console.log(arr)  // [2, "a", "b", "c", undefined, null]
console.log(arr2)  // ["212", "a12", "b12", "c12", "undefined12", "null12"]
Copy the code

You can call it chained

let arr = [1.2.3]
let tmp = arr.map(item= > item + 1).map(item= > item + 1)
console.log(tmp)  / / [3, 4, 5]
Copy the code

Map can also pass in a second parameter to bind the this variable inside the callback function

let arr = [1.2]
let arr2 = [3.4]
let tmp = arr.map(function(item, index){
    return this[index]
}, arr2)
console.log(tmp)  / / [3, 4]
Copy the code

filter

It doesn’t change the original array, it returns the new array

let arr = [1.2.3.4.5.6]
let tmp = arr.filter(item= > {
    return item % 2= = =0
})
console.log(tmp)  / / (2, 4, 6]
Copy the code

Filter can also be passed a second argument to bind the this variable inside the callback function

let arr = ['a'.'b'.'c']
let arr2 = ['aa'.'bb'.'cc']
let tmp = arr.filter(function(item, index){
    return this[index] === 'bb'
}, arr2)
console.log(tmp)  // ["b"]
Copy the code

There is also an operation commonly used to remove false values (undefined, null, false, 0, “, NaN, etc.) from an array

let arr = [1.undefined.2.null.3.false.0.' '.4.NaN]
let tmp = arr.filter(Boolean)
console.log(tmp)  // [1, 2, 3, 4]
Copy the code

for… in

Can be used to iterate over strings, arrays, objects, etc.

let arr = ['a'.'b']
for(let key in arr){
    console.log(arr[key])  // a b
}
Copy the code

Traverses the enumerable properties of an object, but does not traverse the non-enumerable properties of an object

let obj = Object.create(null, {name: {value:'zhangsan'.enumerable: true
    },
    // Age is not enumerable and is not used by for... In loop traversal
    age:{
        value:12.enumerable: false}})console.log(obj)  // {name: "zhangsan", age: 12}
for(let p in obj){
    console.log(p)  // name
    console.log(obj[p])  // zhangsan
}
Copy the code

Iterate over properties on the prototype object. What if you don’t want properties on the prototype object? Use the hasOwnProperty() method to determine filtering

class Person {
    constructor(name){
        this.name = name
    }
}
// Gender is an attribute on the prototype object
Person.prototype.gender = 'male'
let obj = new Person('zhangsan')
for(let p in obj){
    if(obj.hasOwnProperty(p)){
        console.log(p)  // name
    }
    console.log(p)  // name gender 
}
Copy the code

for… In also iterates over the attributes of the array itself. Due to a historical legacy, it actually iterates over the property names of the object. Arrays are also objects in which the index of each element is treated as an attribute. So when we manually add extra properties to the array, it will be iterated over.

let arr = [1.2]
arr.name = 'array1'
for(let p in arr){
    console.log(arr[p])  // 1 2 array1
}
Copy the code

for… The in loop outputs the name attribute. But the length attribute is not included. The of loop fixes these problems, and let’s look at this guy from ES6.

for… of

Iterate over objects that have iterators such as strings, arrays, arrays of classes (Arguments objects,DOM NodeList objects), maps, sets, generators, etc., and can respond to break,continue, and return statements. Iterates over a Map

let arr = [['name'.'zhangsan'], ['age'.12]]
let map = new Map(arr)
for(let [key, value] of map){
    console.log(key)  // name age
    console.log(value)  // zhangsan 12
}
Copy the code

Use the continue statement to control the flow, just as you would in a for loop

let arr = [1.2.3.4.5.6]
for(let item of arr){
    if(item % 2= = =0) {continue
    }
    console.log(item)  / / 1 3 5
}
Copy the code

Now that we’re talking about for… “Of,” then it’s worth mentioning Iterator. Iterator is an interface that provides uniform access to different data structures. Let’s look at the following code first

let obj = {}
for(let item of obj){
    console.log(item)  // Uncaught TypeError: obj is not iterable
}
Copy the code

The code went viral, indicating that OBJ is not iterable. This is because obj does not have a built-in Iterator for… But if we want to use for… What if of iterates over an OBj object?

One method provided here is that the object’s symbol. iterator property points to the object’s default iterator method. So we just manually add a Symbol. Iterator property to the object

let obj = {}
obj[Symbol.iterator] = function* (){
    yield 'a'
    yield 'b'
}
for(let item of obj){
    console.log(item)  // a b
}
Copy the code

As you can see, the OBJ object can now be traversed, becoming more like an array. Suppose we add another line of code at the end and observe the result. Now you’re starting to feel more and more alike.

console.log([...obj])  // ["a", "b"]
Copy the code

for await… of

for await… Of creates iterative loops on an iterable and can only be used inside async function. Suppose we have an array with multiple functions executing asynchronously, and we want to execute each function synchronously

(async function fun(){
    let fn1 = new Promise((resolve, reject) = > {
        setTimeout((a)= > {
            resolve('fn1')},1500)})let fn2 = new Promise((resolve, reject) = > {
        setTimeout((a)= > {
            resolve('fn2')},200)})let fnArr = [fn1, fn2]
    for await (let fn of fnArr){
        console.log(fn)  // fn1 fn2 outputs fn1, then fn2
    }
})()
Copy the code

every

The function evaluates each item in the array and returns true only if each item returns true. In layman’s terms, everyone meets the requirements.

let arr = [1.2.3]
let res = arr.every(item= > item > 0)
console.log(res)  // true
Copy the code

some

If any of the items in the array returns true, the result will return true. In layman’s terms, it only takes one person to meet the requirements.

let arr = [1.2.3]
let res = arr.some(item= > item > 2)
console.log(res)  // true
Copy the code

The methods every and some each take a function, which in turn takes three arguments: the current member of the array, the current index, and the entire array. This takes the same form as map,forEach,map, etc.

find

Returns the first element that matches the test criteria of the function, and stops looking for subsequent elements, or returns undefined if none matches

let arr = [1.2.3]
let res = arr.find(item= > item > 1)
console.log(res)  / / 2
Copy the code

Object.keys

Keys () and Object.values() can be used to obtain the property name, property value, and key-value pair of an Object. Note that object. keys returns the property name of the Object itself and only enumerable properties

let obj = {name:'zhangsan'.age:12.job:'FE engineer'} 
console.log(Object.keys(obj))  // ["name", "age", "job"]
console.log(Object.values(obj))  // ["zhangsan", 12, "FE engineer"]
console.log(Object.entries(obj))  // [["name", "zhangsan"],["age", 12],["job", "FE engineer"]]
Copy the code

Let’s look at the following code to verify this

// Attributes on prototype objects, in for... In is traversed, not found in object. keys
Object.prototype.gender = 'male'
let obj = Object.create({}, {
    name: {value:'zhangsan'.enumerable:true
    },
    // Age is a non-enumerable attribute in for... Neither in nor object. keys
    age:{
        value:12.enumerable:false}})console.log(Object.keys(obj))  // ["name"]
for(let p in obj){
    console.log(p)  // name gender
}
Copy the code

Here you can derive a method to determine whether an object is an empty object

if(Object.keys(obj).length){
    // Not an empty object
}else{
    // Is an empty object
}
Copy the code

conclusion

  • forEachWhich is essentially a loop of arrays, andforLoop statements are similar, but the syntax is simpler. andforEachDoes not change the original array, does not return a new array.
  • mapandfilterThey don’t change the original array, they return a new array. And because it returns a new array, it can be called chained. The difference ismapIs the original array processing, one-to-one relational mapping, andfilterIs to filter the original array and retain the array members that meet the requirements.
  • for... inThe enumerable properties of the object are iterated over, including those on the prototype object. Designed primarily for traversing objects, not for traversing groups of numbers.
  • for... ofTraverse hasIteratorIterator object, avoidedfor... inLoop all defects, and can respond correctlybreak.continueandreturnStatements, etc.
  • for await... ofTurn an asynchronous loop into a synchronous loop
  • everyandsomeA bit like an assertion, returning a Boolean type
  • Object.keys()Returns a string array of all enumerable properties of a given object