SoFunction
Updated on 2025-03-03

Detailed explanation of traversal in JavaScript (multiple traversals)

Object traversal

To facilitate the testing of object traversal, I defined a test object obj below.

Test object

// Set three custom properties for Object (enumerable) = 'userProp';
 = function() {
 return ;
};
// Define an object, implicitly inherit fromvar obj = {
 name: 'percy',
 age: 21,
 [Symbol('symbol attribute')]: 'symbolProp',
 unEnumerable: 'I am an unenumerable property',
 skills: ['html', 'css', 'js'],
 getSkills: function() {
  return ;
 }
};
// Set the unEnumerable property to an unenumerable property(obj, 'unEnumerable', {
 enumerable: false
});

After ES6, there are 5 methods to traverse the properties of the object.

for…in: Iterate over the object's own and inherited enumerable properties (excluding properties of the Symbol type)

for (let key in obj) {
 (key);
 (); // wrong style
 (obj[key]); // right style
}

Do not use for…in to traverse arrays. Although it can be traversed, if you set enumerable properties for , these properties will also be traversed, because arrays are also an object.

(obj): Return an array including all enumerable properties of the object itself (excluding inherited) (excluding properties of Symbol type)

(obj); 
// ["name", "age", "skills", "getSkills"]

(obj): Return an array containing all properties of the object itself (excluding properties of Symbol type, not including inherited properties, but include non-enumerable properties)

(obj);
// ["name", "age", "unEnumerable", "skills", "getSkills"]

(obj):Returns an array containing all Symbol-type properties of the object itself (excluding inherited properties)

(obj);
// [Symbol(symbol property)]

(obj): Return an array containing all properties of the object itself (including properties of Symbol type, and properties that are not enumerable, but do not include inherited properties)

(obj);
// ["name", "age", "unEnumerable", "skills", "getSkills", Symbol(symbol attribute)]

The above five methods traverse the properties of the object, and all follow the same order rules for property traversal.

  • First iterate through all attributes with attribute names and sort by number
  • Secondly, iterate through all attributes whose attributes are named strings and sort them according to the generation time.
  • Finally iterate through all attributes with attribute names Symbol values ​​and sort them according to the generation time

How to determine whether a certain attribute is an object's own attribute?
useinOperator (not rigorous, it actually determines that this property is not on the prototype chain of the object)

'age' in obj;  // true
'userProp' in obj; // true (userProp is a property on the obj prototype chain)'name' in Object; // true 
// The reason for the above is true is that Object is a constructor, and the function happens to have a name attribute;   // 'Object'
;   // 'Array'

usehasOwnProperty(), This method will only detect attributes on an object, not attributes on the prototype chain.

('age');  // true
('skills'); // true
('userProp'); // false

But it still has shortcomings. Give an example ~

// Create a new object using () and this object does not have any prototype chainvar obj2 = (null, {
 name: { value: 'percy' },
 age: { value: 21 },
 skills: { value: ['html', 'css', 'js'] }
});
('name'); // Report an error('skills'); // Report an error

In view of the above situation, we use a more complete solution to solve it.
Use (obj,'prop'…)

(obj2,'name');  // true
(obj2,'skills'); // true
(obj2,'userProp'); // false

Array traversal

Arrays are actually also an object, so you can also use any method of object traversal above (but pay attention to the scale). In addition, arrays also have other traversal methods.
The most basic for loop and while loop traversal (the flaw is that an additional count variable is added)
ES6 introduces: for…of , there is no such count variable now, but it is not concise enough (I won't introduce it in detail here, I will write it later)

for(let value of arr){
 (value);
}

Here are some built-in traversal methods for arrays
(): Executes the provided function once on each element of the array

(callback(currentValue, index, array){
 // do something
}[,thisArg]);
// If the array is modified during iteration, continue to traverse the modified array according to the indexvar words = ["one", "two", "three", "four"];
(function(word) {
 (word);
 if (word === "two") {
 ();
 }
});
// one
// two
// four

(): Returns a new array, each element is the value returned by the callback function

(callback(currentValue, index, array){
  // do something 
}[,thisArg]);
``` 
```js
// A pit of map[1,2,3].map(parseInt); // [1, NaN, NaN]
// Prompt map(currentValue,index,array)//  parseInt(value,base)

  • Some useful built-in array methods (similar to map, the three parameters of the callback function)

    • (callback[, thisArg]): Test whether each element of the array has passed the callback function test. If all pass, return true, otherwise return false (the local essence point means that if the value returned by the callback function is true each time, every() returns true, otherwise false)
    • (callback[,thisArg]): Returns a new array, and the elements of the array are elements that passed the test in the original array (if the callback function returns true, the corresponding elements will enter the new array)
    • (callback[, thisArg]): Returns the first element that passed the test
    • (callback[, thisArg]): Similar to the above function, except that this returns the index
    • (callback[, thisArg]): Similar to find(), except that it does not return an element, it only returns a boolean value. As long as a test is found, it returns true
  • (callback,[initialValue]): It is habitually called the accumulator function. It executes a callback function on each element of the array and returns a value at the end (this value is the value returned when the callback function was last called)

    • The callback function of this function has 4 parameters
      • accumulator: The value returned by the last callback function
      • currentValue: The value currently being processed
      • currentIndex
      • array
    • initialValue: Optional, whose value is used for the first parameter of callback
  • (callback[, initialValue]): The usage is the same as the function above, except that the traversal direction is exactly the opposite.

// Some related cases// Perform the array to accumulate, multiply and other operations[1,10,5,3,8].reduce(function(accumulator,currentValue){
 return accumulator*currentValue;
}); // 1200
// Array flattening[[0, 1], [2, 3], [4, 5]].reduce(function(a, b) {
 return (b);
}); // [0, 1, 2, 3, 4, 5]
[[0, 1], [2, 3], [4, 5]].reduceRight(function(a, b) {
 return (b);
}); // [4, 5, 2, 3, 0, 1]

Summarize the commonality of the above functions

  • It is logically operated or judged by the return value of each callback function.
  • Callback functions can be written as simpler arrow functions (recommended)
  • All can operate strings by shaped like (str, callback)
var str = '123,hello';
// Invert the string(str,function(a,b){
 return a+b;
}); // olleh,321
// Filter strings, retain only lowercase letters('123,hello', function(a) {
 return /[a-z]/.test(a);
}).join(''); // hello
// Use map to traverse strings (this example is obviously not very good *_*)(str,function(a){
 return ();
}); // ["1", "2", "3", ",", "H", "E", "L", "L", "O"]

What the following article wants to say is that we can traverse the array with a more concise syntax (such as built-in functions) to eliminate the loop structure.

References:Loopless JavaScript