Manipulating arrays in the ES5 way
Some years ago when the support of ES5 features was poor (EcmaScript 5th edition was finalized in 2009), libraries such as Underscore and Lo-Dash got highly popular as they provided a comprehensive set of utilities to deal with arrays/collections. Today, many developers still use third-party libraries (including jQuery/Zepro) for methods such as map
, filter
, every
, some
, reduce
, and indexOf
, while these are available in the native form of JavaScript. It still depends on how you use such libraries, but it may likely happen that you don't need them anymore. Let's see what we have now in JavaScript.
Array methods in ES5
Array.prototype.forEach
is probably the most used method of the arrays. That is, it is the native implementation of _.each
, or for example, of the $.each
utilities. As parameters, forEach
expects an iteratee
callback function and optionally a context in which you want to execute the callback. It passes to the callback function an element value, an index, and the entire array. The same parameter syntax is used for most array manipulation methods. Note that jQuery's $.each
has the inverted callback parameters order:
"use strict"; var data = [ "bar", "foo", "baz", "qux" ]; data.forEach(function( val, inx ){ console.log( val, inx ); });
Array.prototype.map
produces a new array by transforming the elements of a given array:
"use strict"; var data = { bar: "bar bar", foo: "foo foo" }, // convert key-value array into url-encoded string urlEncStr = Object.keys( data ).map(function( key ){ return key + "=" + window.encodeURIComponent( data[ key ] ); }).join( "&" ); console.log( urlEncStr ); // bar=bar%20bar&foo=foo%20foo
Array.prototype.filter
returns an array, which consists of given array values that meet the callback's condition:
"use strict"; var data = [ "bar", "foo", "", 0 ], // remove all falsy elements filtered = data.filter(function( item ){ return !!item; }); console.log( filtered ); // ["bar", "foo"]
Array.prototype.reduce
/Array.prototype.reduceRight
retrieves the product of values in an array. The method expects a callback function and optionally the initial value as arguments. The callback function receive four parameters: the accumulative value, current one, index and original array. So we can, for an instance, increment the accumulative value by the current one (return acc += cur;) and, thus, we will get the sum of array values.
Besides calculating with these methods, we can concatenate string values or arrays:
"use strict"; var data = [[ 0, 1 ], [ 2, 3 ], [ 4, 5 ]], arr = data.reduce(function( prev, cur ) { return prev.concat( cur ); }), arrReverse = data.reduceRight(function( prev, cur ) { return prev.concat( cur ); }); console.log( arr ); // [0, 1, 2, 3, 4, 5] console.log( arrReverse ); // [4, 5, 2, 3, 0, 1]
Array.prototype.some
tests whether any (or some) values of a given array meet the callback condition:
"use strict"; var bar = [ "bar", "baz", "qux" ], foo = [ "foo", "baz", "qux" ], /** * Check if a given context (this) contains the value * @param {*} val * @return {Boolean} */ compare = function( val ){ return this.indexOf( val ) !== -1; }; console.log( bar.some( compare, foo ) ); // true
In this example, we checked whether any of the bar array values are available in the foo
array. For testability, we need to pass a reference of the foo
array into the callback. Here we inject it as context. If we need to pass more references, we would push them in a key-value object.
As you probably noticed, we used in this example Array.prototype.indexOf
. The method works the same as String.prototype.indexOf
. This returns an index of the match found or -1
.
Array.prototype.every
tests whether every value of a given array meets the callback condition:
"use strict"; var bar = [ "bar", "baz" ], foo = [ "bar", "baz", "qux" ], /** * Check if a given context (this) contains the value * @param {*} val * @return {Boolean} */ compare = function( val ){ return this.indexOf( val ) !== -1; }; console.log( bar.every( compare, foo ) ); // true
If you are still concerned about support for these methods in a legacy browser as old as IE6-7, you can simply shim them with https://github.com/es-shims/es5-shim.
Array methods in ES6
In ES6, we get just a few new methods that look rather like shortcuts over the existing functionality.
Array.prototype.fill
populates an array with a given value, as follows:
"use strict"; var data = Array( 5 ); console.log( data.fill( "bar" ) ); // ["bar", "bar", "bar", "bar", "bar"]
Array.prototype.includes
explicitly checks whether a given value exists in the array. Well, it is the same as arr.indexOf( val ) !== -1
, as shown here:
"use strict"; var data = [ "bar", "foo", "baz", "qux" ]; console.log( data.includes( "foo" ) );
Array.prototype.find
filters out a single value matching the callback condition. Again, it's what we can get with Array.prototype.filter
. The only difference is that the filter method returns either an array or a null value. In this case, this returns a single element array, as follows:
"use strict"; var data = [ "bar", "fo", "baz", "qux" ], match = function( val ){ return val.length < 3; }; console.log( data.find( match ) ); // fo