for (element in array)
(imperative). If so, use a while
or for
loop (imperative) or Array.prototype.forEach()
(declarative). To transform elements of an array, use Array.prototype.map()
; to filter an array, use Array.prototype.filter()
; to resolve or concatenate values in an array, use Array.prototype.reduce()
.If you use meaningful callback function parameter names and indentation, these method calls are largely self-documenting even when chained:
function pigLatin(str) {
return str.toLowerCase().split(' ')
.map(function(word) {
return word.substring(1) +
word.charAt(0) + 'ay';
}).join(' ');
}
console.log(pigLatin('Pig latin')); // => igPay atinlay
igpay atinlay
undefined
function makeStrConcatenator(str) {
return function(val) {
return str + val;
}
}
var fooConcatenator = makeStrConcatenator('foo');
console.log(fooConcatenator('blue')); // => 'fooblue'
console.log(fooConcatenator(true)); // => 'footrue'
fooblue footrue
undefined
function terseTest(exp) {
return exp
? 'success '
: 'FAILURE '
}
// Expects an array of objects resembling {input: 'foo', output: 'foobar'}
function testResults(testFunction, reporter, tests) {
var keys, results = '';
tests.forEach(function (test) {
keys = Object.keys(test);
results += reporter(testFunction(test[keys[0]]) === test[keys[1]]);
});
return results;
}
undefined
// Imperative solution using iteration, ES1 for..in
function addLength(str) {
var arr = str.split(' '), elt, word;
for (elt in arr) {
word = arr[elt];
arr[elt] = word + ' ' + word.length;
}
return arr;
}
// Imperative solution using iteration, ES5 forEach()
function addLength(str) {
var arr = str.split(' ');
arr.forEach(function(val, ind, arr) {
arr[ind] = val + ' ' + val.length;
});
return arr;
}
// Declarative solution, ES5 map()
function addLength(str) {
return str.split(' ').map(function(val) {
return val + ' ' + val.length;
});
}
// Declarative solution, ES5 map(), ES6 arrow function
// function addLength(str) {
// return str.split(' ').map(val => val + ' ' + val.length);
// }
console.log(addLength('foo bar')); // => ["foo 3", "bar 3"]
[ 'foo 3', 'bar 3' ]
undefined
function returnSparse(arr) {
var dense = [];
for (var i = 0, len = arr.length; i < len; i++) {
if (arr[i] !== null && arr[i] !== undefined)
dense.push(arr[i]);
}
return dense;
}
var sparse = [1,,null,,2,,null,undefined,,3,,4,5,,,10];
console.log(returnSparse(sparse)); // => [1, 2, 3, 4, 5, 10];
[ 1, 2, 3, 4, 5, 10 ]
undefined
Using Array.prototype.filter()
:
function returnSparse(arr) {
return arr.filter(function(val) {
return val !== null && val !== undefined;
});
}
var sparse = [1,,null,,2,,null,undefined,,3,,4,5,,,10];
console.log(returnSparse(sparse)); // => [1, 2, 3, 4, 5, 10];
[ 1, 2, 3, 4, 5, 10 ]
undefined
With ES6 arrow function:
// TODO: add output once Node supports arrow functions
function returnSparse(arr) {
return arr.filter(val =>
val !== null && val !== undefined
);
}
var sparse = [1,,null,,2,,null,undefined,,3,,4,5,,,10];
console.log(returnSparse(sparse)); // => [1, 2, 3, 4, 5, 10];
// Imperative solution using iteration.
function removeFalsey(arr) {
var out = [];
for (var elt in arr) if (arr[elt]) out.push(arr[elt]);
return out;
}
// Imperative solution using recursion.
function removeFalsey(arr) {
while (arr.some(function(elt) { return (!elt) })) {
var first = arr.shift();
if (!!first) arr.push(first);
removeFalsey(arr);
}
return arr;
}
// Declarative solution.
function removeFalsey(arr) {
return arr.filter(function(elt) {
return (!!elt);
});
}
// Using ES6 arrow function.
function removeFalsey(arr) {
return arr.filter(elt => (!!elt));
}
Imperative solution, using a new string:
function insertDash(num) {
var dashed = ''; num = num.toString();
for (var i = 0, len = num.length; i < len; i++) {
dashed += num[i];
if (num[i] !== '0' && // Don't treat zero as odd
i !== len - 1 && // Don't append dash to last numeral
Number(num[i]) % 2 !== 0 &&
Number(num[i + 1]) % 2 !== 0) dashed += '-';
}
return dashed;
}
var testInsertDash = function() {
var testFunction = insertDash,
reporter = terseTest,
tests = [
{i: 333565, o: '3-3-3-565'},
{i: 454703, o: '454703'},
{i: 454793, o: '4547-9-3'}
];
console.log(testResults(testFunction, reporter, tests));
}
testInsertDash();
success success success
undefined
Recursive solution with regexp:
function insertDash(num) {
var re = /([13579](?=[13579]))/;
num = num.toString();
while (re.test(num)) {
num = num.replace(re, "$1-");
insertDash(num);
}
return num;
}
testInsertDash();
success success success
undefined
Declarative solution, using Array.prototype.reduce
. The first value passed to the callback will be the entire concatenated string in each case, so we need a regexp that finds odd numbers only at the end of the expression:
'333565'.split('').reduce(function(a, b) {
console.log('[' + a + ']', '[' + b + ']');
return (/[13579]$/.test(a) && /[13579]$/.test(b))
? (a + '-' + b)
: (a + b);
});
[3] [3] [3-3] [3] [3-3-3] [5] [3-3-3-5] [6] [3-3-3-56] [5]
'3-3-3-565'
function insertDash(num) {
var arr = num.toString().split(''),
re = /[13579]$/;
return arr.reduce(function (a, b) {
return (re.test(a) && re.test(b))
? (a + '-' + b)
: (a + b);
});
}
testInsertDash();
success success success
undefined
Declarative solution, ES6 arrow function:
function insertDash(num) {
var arr = num.toString().split(''),
re = /[13579]$/;
return arr.reduce((a, b) =>
(re.test(a) && re.test(b))
? (a + '-' + b)
: (a + b)
);
}
Treating lowercase characters as numbers.
Imperative solution:
function camelToSnake(string) {
var re = /([A-Z]{1}[a-z0-9]*)/g,
words = string.match(re),
snaked = '';
for (var i = 0, len = words.length; i < len; i++) {
snaked += (i != len - 1) ? (words[i] + '_') : words[i];
}
return snaked.toLowerCase();
}
var testCamelToSnake = function() {
var testFunction = camelToSnake,
reporter = terseTest,
tests = [
{i: 'TestController', o: 'test_controller'},
{i: 'MoviesAndBooks', o: 'movies_and_books'},
{i: 'App7Test', o: 'app7_test'}
];
console.log(testResults(testFunction, reporter, tests));
}
testCamelToSnake();
success success success
undefined
Declarative solution using String.prototype.match()
:
function camelToSnake(string) {
var re = /([A-Z]{1}[a-z0-9]*)/g;
return string.match(re).join('_').toLowerCase();
}
testCamelToSnake();
success success success
undefined
Declarative solution using String.prototype.split()
and a regexp with lookahead assertion. If a regexp contains grouping parentheses, the split()
method splices the portion of the match between grouping parens into the output array.
function camelToSnake(string) {
var re = /(?=[A-Z])/; // Split on anything followed by [A-Z]
return string.split(re).join('_').toLowerCase();
}
testCamelToSnake();
success success success
undefined