/** * @file obj.js * @module obj */ /** * @callback obj:EachCallback * * @param {Mixed} value * The current key for the object that is being iterated over. * * @param {string} key * The current key-value for object that is being iterated over */ /** * @callback obj:ReduceCallback * * @param {Mixed} accum * The value that is accumulating over the reduce loop. * * @param {Mixed} value * The current key for the object that is being iterated over. * * @param {string} key * The current key-value for object that is being iterated over * * @return {Mixed} * The new accumulated value. */ const toString = Object.prototype.toString; /** * Array-like iteration for objects. * * @param {Object} object * The object to iterate over * * @param {obj:EachCallback} fn * The callback function which is called for each key in the object. */ export function each(object, fn) { Object.keys(object).forEach(key => fn(object[key], key)); } /** * Array-like reduce for objects. * * @param {Object} object * The Object that you want to reduce. * * @param {Function} fn * A callback function which is called for each key in the object. It * receives the accumulated value and the per-iteration value and key * as arguments. * * @param {Mixed} [initial = 0] * Starting value * * @return {Mixed} * The final accumulated value. */ export function reduce(object, fn, initial = 0) { return Object.keys(object).reduce( (accum, key) => fn(accum, object[key], key), initial); } /** * Object.assign-style object shallow merge/extend. * * @param {Object} target * @param {Object} ...sources * @return {Object} */ export function assign(target, ...sources) { if (Object.assign) { return Object.assign(target, ...sources); } sources.forEach(source => { if (!source) { return; } each(source, (value, key) => { target[key] = value; }); }); return target; } /** * Returns whether a value is an object of any kind - including DOM nodes, * arrays, regular expressions, etc. Not functions, though. * * This avoids the gotcha where using `typeof` on a `null` value * results in `'object'`. * * @param {Object} value * @return {Boolean} */ export function isObject(value) { return !!value && typeof value === 'object'; } /** * Returns whether an object appears to be a "plain" object - that is, a * direct instance of `Object`. * * @param {Object} value * @return {Boolean} */ export function isPlain(value) { return isObject(value) && toString.call(value) === '[object Object]' && value.constructor === Object; }