Prefer traversal methods rather than loops
When using loops, it is easy to violate the DRY (Don't Repeat Yourself) principle. This is because we usually choose the copy-paste method to avoid hand-writing paragraphs of circular statements. But doing so will result in a lot of duplicate code in the code, and developers will "reinvent the wheel" meaninglessly. More importantly, it is easy to overlook the details in the loop when copying and pasting, such as the starting index value, termination condition, etc.
For example, the following for loop has this problem. Assume n is the length of the collection object:
for (var i = 0; i <= n; i++) { ... } // 终止条件错误,应该是i < n for (var i = 1; i < n; i++) { ... } // 起始变量错误,应该是i = 0 for (var i = n; i >= 0; i--) { ... } // 起始变量错误,应该是i = n - 1 for (var i = n - 1; i > 0; i--) { ... } // 终止条件错误,应该是i >= 0
It can be seen that it is easy to deal with some details of the loop. Something went wrong. Using the closure provided by JavaScript (see Item 11), the details of the loop can be encapsulated for reuse. In fact, ES5 provides some methods to deal with this problem. Among them, Array.prototype.forEach is the simplest one. Using it, we can write the loop like this:
// 使用for循环 for (var i = 0, n = players.length; i < n; i++) { players[i].score++; } // 使用forEach players.forEach(function(p) { p.score++; });
In addition to traversing the collection object, another common pattern is to traverse each element in the original collection To perform some operation and then get a new collection, we can also use the forEach method to implement the following:
// 使用for循环 var trimmed = []; for (var i = 0, n = input.length; i < n; i++) { trimmed.push(input[i].trim()); } // 使用forEach var trimmed = []; input.forEach(function(s) { trimmed.push(s.trim()); });
But due to this method, one collection is converted into another collection The pattern is very common. ES5 also provides the Array.prototype.map method to make the code simpler and more elegant:
var trimmed = input.map(function(s) { return s.trim(); });
In addition, there is another common pattern that is to set Filter according to certain conditions, and then obtain a subset of the original collection. Array.prototype.filter is provided in ES5 to implement this mode. This method accepts a Predicate as a parameter, which is a function that returns true or false: returning true means that the element will be retained in the new collection; returning false means that the element will not appear in the new collection. For example, we use the following code to filter product prices and only retain products with prices in the [min, max] range:
##
listings.filter(function(listing) { return listing.price >= min && listing.price <= max; });
function takeWhile(a, pred) { var result = []; for (var i = 0, n = a.length; i < n; i++) { if (!pred(a[i], i)) { break; } result[i] = a[i]; } return result; } var prefix = takeWhile([1, 2, 4, 8, 16, 32], function(n) { return n < 10; }); // [1, 2, 4, 8]
Array.prototype.takeWhile = function(pred) { var result = []; for (var i = 0, n = this.length; i < n; i++) { if (!pred(this[i], i)) { break; } result[i] = this[i]; } return result; }; var prefix = [1, 2, 4, 8, 16, 32].takeWhile(function(n) { return n < 10; }); // [1, 2, 4, 8]
function takeWhile(a, pred) { var result = []; a.forEach(function(x, i) { if (!pred(x)) { // ? } result[i] = x; }); return result; }
function takeWhile(a, pred) { var result = []; var earlyExit = {}; // unique value signaling loop break try { a.forEach(function(x, i) { if (!pred(x)) { throw earlyExit; } result[i] = x; }); } catch (e) { if (e !== earlyExit) { // only catch earlyExit throw e; } } return result; }
[1, 10, 100].some(function(x) { return x > 5; }); // true [1, 10, 100].some(function(x) { return x < 0; }); // false [1, 2, 3, 4, 5].every(function(x) { return x > 0; }); // true [1, 2, 3, 4, 5].every(function(x) { return x < 3; }); // false
function takeWhile(a, pred) { var result = []; a.every(function(x, i) { if (!pred(x)) { return false; // break } result[i] = x; return true; // continue }); return result; }
The above is the detailed content of Detailed explanation of why traversal method is preferred over loop code in JavaScript. For more information, please follow other related articles on the PHP Chinese website!