preface

When it comes to traversal in Javascript, there are two types of traversal: array traversal and object traversal.

Below we will summarize comb through all the JS array traversal and object traversal methods.

PS: Javascript here refers to JS in a broad sense, including ES6 methods.

Array traversal

JavaScript provides multiple traversal syntax.

The for loop

The original way to write it is the for loop.

 for (var index = 0; index < myArray.length; index++) {
   console.log(myArray[index]);
 }
Copy the code

forEachmethods

This is cumbersome, so arrays provide built-in forEach methods.

 myArray.forEach(function (value) {
   console.log(value);
 });
Copy the code

The problem with this is that you can’t jump out of itforEachCycle,breakCommand orreturnOrders are not effective.

for... incycle

for… The in loop iterates through the array’s key names and accesses the array’s value through the array’s key.

 for (var index in myArray) {
   console.log(myArray[index]);
 }
Copy the code

for... inLoops have several disadvantages:

  • The array’s key name is a number, butfor... inLoops are strings with keys “0”, “1”, “2”, and so on.
  • for... inThe loop iterates not only over numeric key names, but also over other manually added keys, and even keys on the prototype chain.
  • In some cases,for... inThe loop iterates over the key names in any order.

All in all, for… The in loop is designed primarily for traversing objects, not for traversing groups of numbers. Therefore, it is not recommended to be used in traversal groups.

for... ofcycle

for… The of loop is new in ES6.

 for (let value of myArray) {
   console.log(value);
 }
Copy the code

for… The of loop has some significant advantages over the above approaches.

  • With withfor... inSame concise syntax, but nofor... inThose flaws.
  • Different from theforEachMethod, it can be withbreak,continueandreturnUse together.
  • Provides a unified operation interface for traversing all data structures.

Here is a statement that uses the break statement to break for… An example of an of loop.

 for (var n of fibonacci) {
   if (n > 1000)
     break;
   console.log(n);
 }
Copy the code

The example above prints Fibonacci numbers less than or equal to 1000. If the current item is greater than 1000, the for… statement is broken. Of circulation.

Object traversal

Object traversal, to be precise, should be understood as traversal of object properties. Because as long as you get the name of the object, the value of the object is naturally no problem, you can easily get it.

The enumeration of

Each property of an object has a Descriptor that controls the behavior of the property.

The description of the Object. GetOwnPropertyDescriptor method can obtain the attribute Object.

 let obj = { foo: 123 };
 Object.getOwnPropertyDescriptor(obj, 'foo')
 //  {
 // value: 123,
 // writable: true,
 // enumerable: true,
 // configurable: true
 / /}
Copy the code

An enumerable property that describes an object is called “enumerable.” If it is false, it means that some operations ignore the current property.

Currently, four operations are ignoredenumerableforfalseProperties.

  • for... inLoop: Only the enumerable properties of the object itself and its inheritance are iterated over.
  • Object.keys(): returns the key names of all the enumerable properties of the object itself.
  • JSON.stringify(): Serializes only enumerable properties of the object itself.
  • Object.assign(): ignoreenumerableforfalseOnly enumerable properties of the object itself are copied.

Of the four operations, the first three are available in ES5, and the last object.assign () is new in ES6. Among them, only… In returns the inherited properties, and the other three methods ignore the inherited properties and process only the properties of the object itself.

In fact, the original purpose of enumerable was to make it possible for certain properties to bypass for… In operation, otherwise all internal properties and methods will be traversed. For example, the toString method of an object prototype and the length property of an array are “enumerable” to avoid being used for… Go through to.

 Object.getOwnPropertyDescriptor(Object.prototype, 'toString').enumerable
 // false
 ​
 Object.getOwnPropertyDescriptor([], 'length').enumerable
 // false
Copy the code

In the code above, both toString and Length are Enumerable false, so for… In does not iterate over these two attributes inherited from the stereotype.

In addition, ES6 states that all Class stereotype methods are non-enumerable.

 Object.getOwnPropertyDescriptor(class {foo() {}}.prototype, 'foo').enumerable
 // false
Copy the code

In general, the introduction of inherited properties into operations can complicate matters, and most of the time, we only care about the properties of the object itself. So, try not to use for… In loop and use object.keys () instead.

Property traversal method

ES6 has five methods for traversing an object’s properties.

for… in

for... inLoop over the enumerable properties of the object itself and its inheritance (excluding the Symbol attribute).

for... inLoops are used to iterate over all properties of an object.

 var obj = {a: 1.b: 2.c: 3};
 
 for (var i in obj) {
   console.log('key name:', i);
   console.log('Key:', obj[i]);
 }
 // key name: a
 // Key: 1
 // key name: b
 // Key: 2
 // key name: c
 // Key: 3
Copy the code

for... inThere are two usage considerations for loops.

  • It iterates over all of the object’s enumerable properties and skips those that are not.
  • It traverses not only the properties of the object itself, but also the inherited properties.

For example, objects inherit the toString attribute, but for… The in loop does not traverse this property.

 var obj = {};
 ​
 // The toString attribute exists
 obj.toString // toString() { [native code] }
 ​
 for (var p in obj) {
   console.log(p);
 } // There is no output
Copy the code

In the code above, the object obj inherits the toString attribute, which is not used by the for… The in loop iterates through to because it is “non-traversal” by default. For the traversability of Object attributes, see the Object chapter in the Standard Library.

If the inherited property is traversable, it will be for… In loops through to. In general, however, you just want to iterate over the properties of the object itself, so use for… In, you should use the hasOwnProperty method inside the loop to determine if a property is a property of the object itself.

 var person = { name: 'Lao zhang' };
 
 for (var key in person) {
   if (person.hasOwnProperty(key)) {
     console.log(key); }}// name
Copy the code

Object.keys(obj)

Keys returns an array containing the key names of all of the Object’s own (not inherited) enumerable properties (not including the Symbol property).

Object.getOwnPropertyNames(obj)

Object. GetOwnPropertyNames returns an array containing all attributes of the Object itself (excluding Symbol attribute, but cannot be enumerated attribute) of keys.

Object.getOwnPropertySymbols(obj)

Object. GetOwnPropertySymbols returns an array containing all the Symbol attribute of the Object itself the key name.

With the Object. GetOwnPropertyNames (), you can take all of the given Object Symbol attribute as a Symbol for an array. . Please note that the Object getOwnPropertyNames () itself does not contain Symbol attribute of the Object, only contain the string properties.

Because all objects in the initialization will not contain any Symbol, unless you assign the Symbol on the Object Object. GetOwnPropertySymbols () will return an empty array.

The sample

 var obj = {};
 var a = Symbol("a");
 var b = Symbol.for("b");
 ​
 obj[a] = "localSymbol";
 obj[b] = "globalSymbol";
 ​
 var objectSymbols = Object.getOwnPropertySymbols(obj);
 ​
 console.log(objectSymbols.length); / / 2
 console.log(objectSymbols)         // [Symbol(a), Symbol(b)]
 console.log(objectSymbols[0])      // Symbol(a)
Copy the code

Reflect.ownKeys(obj)

Reflect.ownKeys returns an array containing all of the object’s own (not inherited) key names, whether they are symbols or strings or enumerable.


All five methods follow the same sequence rules for traversal of attributes.

  • First, all numeric keys are iterated, sorted in ascending order.
  • Next, all the string keys are iterated in ascending order by the time they were added.
  • Finally, all Symbol keys are iterated in ascending order of time they were added.
 Reflect.ownKeys({ [Symbol()] :0.b:0.10:0.2:0.a:0 })
 // ['2', '10', 'b', 'a', Symbol()]
Copy the code

In the above code, the reflect. ownKeys method returns an array containing all the properties of the argument object. The array’s properties are in this order, starting with the numeric properties 2 and 10, followed by the string properties B and A, and finally the Symbol property.

conclusion

Finally, let’s sum up:

In array traversal, it is recommended to use for… of … Loops. ForEach is also a good choice for loops that do not require break or continue.

When traversing Object properties, in most cases we don’t want to get the properties that the Object inherits, so we usually use object.keys (obj) for traversal. In other cases, we need to select an appropriate traversal method according to the requirements of object traversal.

If you think my article is helpful to you, please give a lot of support! At the same time, you are very welcome to follow my Github!