Object
bindAll
将对象的方法绑定到对象本身,覆盖现有方法。
使用 Array.prototype.forEach()
返回一个 function
,该函数使用 function.prototype.apply()
为每个指定的函数将给定的上下文(obj
) 应用于 fn
。
const bindAll = (obj, ...fns) => fns.forEach( fn => ( (f = obj[fn]), (obj[fn] = function() { return f.apply(obj); }) ) );
var view = { label: 'docs', click: function() { console.log('clicked ' + this.label); } }; bindAll(view, 'click'); jQuery(element).on('click', view.click); // Logs 'clicked docs' when clicked.
deepClone
Creates a deep clone of an object.
Use recursion. Use Object.assign()
and an empty object ({}
) to create a shallow clone of the original. Use Object.keys()
and Array.prototype.forEach()
to determine which key-value pairs need to be deep cloned.
const deepClone = obj => { let clone = Object.assign({}, obj); Object.keys(clone).forEach( key => (clone[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key]) ); return Array.isArray(obj) && obj.length ? (clone.length = obj.length) && Array.from(clone) : Array.isArray(obj) ? Array.from(obj) : clone; };
const a = { foo: 'bar', obj: { a: 1, b: 2 } }; const b = deepClone(a); // a !== b, a.obj !== b.obj
deepFreeze
Deep freezes an object.
Calls Object.freeze(obj)
recursively on all unfrozen properties of passed object that are instanceof
object.
const deepFreeze = obj => Object.keys(obj).forEach( prop => !(obj[prop] instanceof Object) || Object.isFrozen(obj[prop]) ? null : deepFreeze(obj[prop]) ) || Object.freeze(obj);
'use strict'; const o = deepFreeze([1, [2, 3]]); o[0] = 3; // not allowed o[1][0] = 4; // not allowed as well
deepGet
Returns the target value in a nested JSON object, based on the keys
array.
Compare the keys you want in the nested JSON object as an Array
. Use Array.prototype.reduce()
to get value from nested JSON object one by one. If the key exists in object, return target value, otherwise, return null
.
const deepGet = (obj, keys) => keys.reduce((xs, x) => (xs && xs[x] ? xs[x] : null), obj);
let index = 2; const data = { foo: { foz: [1, 2, 3], bar: { baz: ['a', 'b', 'c'] } } }; deepGet(data, ['foo', 'foz', index]); // get 3 deepGet(data, ['foo', 'bar', 'baz', 8, 'foz']); // null
deepMapKeys
Deep maps an object keys.
Creates an object with the same values as the provided object and keys generated by running the provided function for each key.
Use Object.keys(obj)
to iterate over the object's keys. Use Array.prototype.reduce()
to create a new object with the same values and mapped keys using fn
.
const deepMapKeys = (obj, f) => Array.isArray(obj) ? obj.map(val => deepMapKeys(val, f)) : typeof obj === 'object' ? Object.keys(obj).reduce((acc, current) => { const val = obj[current]; acc[f(current)] = val !== null && typeof val === 'object' ? deepMapKeys(val, f) : (acc[f(current)] = val); return acc; }, {}) : obj;
const obj = { foo: '1', nested: { child: { withArray: [ { grandChild: ['hello'] } ] } } }; const upperKeysObj = deepMapKeys(obj, key => key.toUpperCase()); /* { "FOO":"1", "NESTED":{ "CHILD":{ "WITHARRAY":[ { "GRANDCHILD":[ 'hello' ] } ] } } } */
defaults
Assigns default values for all properties in an object that are undefined
.
Use Object.assign()
to create a new empty object and copy the original one to maintain key order, use Array.prototype.reverse()
and the spread operator ...
to combine the default values from left to right, finally use obj
again to overwrite properties that originally had a value.
const defaults = (obj, ...defs) => Object.assign({}, obj, ...defs.reverse(), obj);
defaults({ a: 1 }, { b: 2 }, { b: 6 }, { a: 3 }); // { a: 1, b: 2 }
dig
Returns the target value in a nested JSON object, based on the given key.
Use the in
operator to check if target
exists in obj
. If found, return the value of obj[target]
, otherwise use Object.values(obj)
and Array.prototype.reduce()
to recursively call dig
on each nested object until the first matching key/value pair is found.
const dig = (obj, target) => target in obj ? obj[target] : Object.values(obj).reduce((acc, val) => { if (acc !== undefined) return acc; if (typeof val === 'object') return dig(val, target); }, undefined);
const data = { level1: { level2: { level3: 'some data' } } }; dig(data, 'level3'); // 'some data' dig(data, 'level4'); // undefined
equals
Performs a deep comparison between two values to determine if they are equivalent.
Check if the two values are identical, if they are both Date
objects with the same time, using Date.getTime()
or if they are both non-object values with an equivalent value (strict comparison). Check if only one value is null
or undefined
or if their prototypes differ. If none of the above conditions are met, use Object.keys()
to check if both values have the same number of keys, then use Array.prototype.every()
to check if every key in the first value exists in the second one and if they are equivalent by calling this method recursively.
const equals = (a, b) => { if (a === b) return true; if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime(); if (!a || !b || (typeof a !== 'object' && typeof b !== 'object')) return a === b; if (a === null || a === undefined || b === null || b === undefined) return false; if (a.prototype !== b.prototype) return false; let keys = Object.keys(a); if (keys.length !== Object.keys(b).length) return false; return keys.every(k => equals(a[k], b[k])); };
equals({ a: [2, { e: 3 }], b: [4], c: 'foo' }, { a: [2, { e: 3 }], b: [4], c: 'foo' }); // true
findKey
Returns the first key that satisfies the provided testing function. Otherwise undefined
is returned.
Use Object.keys(obj)
to get all the properties of the object, Array.prototype.find()
to test the provided function for each key-value pair. The callback receives three arguments - the value, the key and the object.
const findKey = (obj, fn) => Object.keys(obj).find(key => fn(obj[key], key, obj));
findKey( { barney: { age: 36, active: true }, fred: { age: 40, active: false }, pebbles: { age: 1, active: true } }, o => o['active'] ); // 'barney'
findLastKey
Returns the last key that satisfies the provided testing function. Otherwise undefined
is returned.
Use Object.keys(obj)
to get all the properties of the object, Array.prototype.reverse()
to reverse their order and Array.prototype.find()
to test the provided function for each key-value pair. The callback receives three arguments - the value, the key and the object.
const findLastKey = (obj, fn) => Object.keys(obj) .reverse() .find(key => fn(obj[key], key, obj));
findLastKey( { barney: { age: 36, active: true }, fred: { age: 40, active: false }, pebbles: { age: 1, active: true } }, o => o['active'] ); // 'pebbles'
flattenObject
Flatten an object with the paths for keys.
Use recursion. Use Object.keys(obj)
combined with Array.prototype.reduce()
to convert every leaf node to a flattened path node. If the value of a key is an object, the function calls itself with the appropriate prefix
to create the path using Object.assign()
. Otherwise, it adds the appropriate prefixed key-value pair to the accumulator object. You should always omit the second argument, prefix
, unless you want every key to have a prefix.
const flattenObject = (obj, prefix = '') => Object.keys(obj).reduce((acc, k) => { const pre = prefix.length ? prefix + '.' : ''; if (typeof obj[k] === 'object') Object.assign(acc, flattenObject(obj[k], pre + k)); else acc[pre + k] = obj[k]; return acc; }, {});
flattenObject({ a: { b: { c: 1 } }, d: 1 }); // { 'a.b.c': 1, d: 1 }
forOwn
Iterates over all own properties of an object, running a callback for each one.
Use Object.keys(obj)
to get all the properties of the object, Array.prototype.forEach()
to run the provided function for each key-value pair. The callback receives three arguments - the value, the key and the object.
const forOwn = (obj, fn) => Object.keys(obj).forEach(key => fn(obj[key], key, obj));
forOwn({ foo: 'bar', a: 1 }, v => console.log(v)); // 'bar', 1
forOwnRight
Iterates over all own properties of an object in reverse, running a callback for each one.
Use Object.keys(obj)
to get all the properties of the object, Array.prototype.reverse()
to reverse their order and Array.prototype.forEach()
to run the provided function for each key-value pair. The callback receives three arguments - the value, the key and the object.
const forOwnRight = (obj, fn) => Object.keys(obj) .reverse() .forEach(key => fn(obj[key], key, obj));
forOwnRight({ foo: 'bar', a: 1 }, v => console.log(v)); // 1, 'bar'
functions
Returns an array of function property names from own (and optionally inherited) enumerable properties of an object.
Use Object.keys(obj)
to iterate over the object's own properties. If inherited
is true
, use Object.get.PrototypeOf(obj)
to also get the object's inherited properties. Use Array.prototype.filter()
to keep only those properties that are functions. Omit the second argument, inherited
, to not include inherited properties by default.
const functions = (obj, inherited = false) => (inherited ? [...Object.keys(obj), ...Object.keys(Object.getPrototypeOf(obj))] : Object.keys(obj) ).filter(key => typeof obj[key] === 'function');
function Foo() { this.a = () => 1; this.b = () => 2; } Foo.prototype.c = () => 3; functions(new Foo()); // ['a', 'b'] functions(new Foo(), true); // ['a', 'b', 'c']
get
Retrieve a set of properties indicated by the given selectors from an object.
Use Array.prototype.map()
for each selector, String.prototype.replace()
to replace square brackets with dots, String.prototype.split('.')
to split each selector, Array.prototype.filter()
to remove empty values and Array.prototype.reduce()
to get the value indicated by it.
const get = (from, ...selectors) => [...selectors].map(s => s .replace(/\[([^\[\]]*)\]/g, '.$1.') .split('.') .filter(t => t !== '') .reduce((prev, cur) => prev && prev[cur], from) );
const obj = { selector: { to: { val: 'val to select' } }, target: [1, 2, { a: 'test' }] }; get(obj, 'selector.to.val', 'target[0]', 'target[2].a'); // ['val to select', 1, 'test']
invertKeyValues
Inverts the key-value pairs of an object, without mutating it. The corresponding inverted value of each inverted key is an array of keys responsible for generating the inverted value. If a function is supplied, it is applied to each inverted key.
Use Object.keys()
and Array.prototype.reduce()
to invert the key-value pairs of an object and apply the function provided (if any). Omit the second argument, fn
, to get the inverted keys without applying a function to them.
const invertKeyValues = (obj, fn) => Object.keys(obj).reduce((acc, key) => { const val = fn ? fn(obj[key]) : obj[key]; acc[val] = acc[val] || []; acc[val].push(key); return acc; }, {});
invertKeyValues({ a: 1, b: 2, c: 1 }); // { 1: [ 'a', 'c' ], 2: [ 'b' ] } invertKeyValues({ a: 1, b: 2, c: 1 }, value => 'group' + value); // { group1: [ 'a', 'c' ], group2: [ 'b' ] }
lowercaseKeys
Creates a new object from the specified object, where all the keys are in lowercase.
Use Object.keys()
and Array.prototype.reduce()
to create a new object from the specified object. Convert each key in the original object to lowercase, using String.toLowerCase()
.
const lowercaseKeys = obj => Object.keys(obj).reduce((acc, key) => { acc[key.toLowerCase()] = obj[key]; return acc; }, {});
const myObj = { Name: 'Adam', sUrnAME: 'Smith' }; const myObjLower = lowercaseKeys(myObj); // {name: 'Adam', surname: 'Smith'};
mapKeys
Creates an object with keys generated by running the provided function for each key and the same values as the provided object.
Use Object.keys(obj)
to iterate over the object's keys. Use Array.prototype.reduce()
to create a new object with the same values and mapped keys using fn
.
const mapKeys = (obj, fn) => Object.keys(obj).reduce((acc, k) => { acc[fn(obj[k], k, obj)] = obj[k]; return acc; }, {});
mapKeys({ a: 1, b: 2 }, (val, key) => key + val); // { a1: 1, b2: 2 }
mapValues
Creates an object with the same keys as the provided object and values generated by running the provided function for each value.
Use Object.keys(obj)
to iterate over the object's keys. Use Array.prototype.reduce()
to create a new object with the same keys and mapped values using fn
.
const mapValues = (obj, fn) => Object.keys(obj).reduce((acc, k) => { acc[k] = fn(obj[k], k, obj); return acc; }, {});
const users = { fred: { user: 'fred', age: 40 }, pebbles: { user: 'pebbles', age: 1 } }; mapValues(users, u => u.age); // { fred: 40, pebbles: 1 }
推荐资源- ES6:正确的部分
学习新的ES6 JavaScript语言特性,如箭头函数,解构,生成器和更多的编写更干净,更有效,可读的程序。
matches
Compares two objects to determine if the first one contains equivalent property values to the second one.
Use Object.keys(source)
to get all the keys of the second object, then Array.prototype.every()
, Object.hasOwnProperty()
and strict comparison to determine if all keys exist in the first object and have the same values.
const matches = (obj, source) => Object.keys(source).every(key => obj.hasOwnProperty(key) && obj[key] === source[key]);
matches({ age: 25, hair: 'long', beard: true }, { hair: 'long', beard: true }); // true matches({ hair: 'long', beard: true }, { age: 25, hair: 'long', beard: true }); // false
matchesWith
Compares two objects to determine if the first one contains equivalent property values to the second one, based on a provided function.
Use Object.keys(source)
to get all the keys of the second object, then Array.prototype.every()
, Object.hasOwnProperty()
and the provided function to determine if all keys exist in the first object and have equivalent values. If no function is provided, the values will be compared using the equality operator.
const matchesWith = (obj, source, fn) => Object.keys(source).every( key => obj.hasOwnProperty(key) && fn ? fn(obj[key], source[key], key, obj, source) : obj[key] == source[key] );
const isGreeting = val => /^h(?:i|ello)$/.test(val); matchesWith( { greeting: 'hello' }, { greeting: 'hi' }, (oV, sV) => isGreeting(oV) && isGreeting(sV) ); // true
merge
Creates a new object from the combination of two or more objects.
Use Array.prototype.reduce()
combined with Object.keys(obj)
to iterate over all objects and keys. Use hasOwnProperty()
and Array.prototype.concat()
to append values for keys existing in multiple objects.
const merge = (...objs) => [...objs].reduce( (acc, obj) => Object.keys(obj).reduce((a, k) => { acc[k] = acc.hasOwnProperty(k) ? [].concat(acc[k]).concat(obj[k]) : obj[k]; return acc; }, {}), {} );
const object = { a: [{ x: 2 }, { y: 4 }], b: 1 }; const other = { a: { z: 3 }, b: [2, 3], c: 'foo' }; merge(object, other); // { a: [ { x: 2 }, { y: 4 }, { z: 3 } ], b: [ 1, 2, 3 ], c: 'foo' }
nest
Given a flat array of objects linked to one another, it will nest them recursively. Useful for nesting comments, such as the ones on reddit.com.
Use recursion. Use Array.prototype.filter()
to filter the items where the id
matches the link
, then Array.prototype.map()
to map each one to a new object that has a children
property which recursively nests the items based on which ones are children of the current item. Omit the second argument, id
, to default to null
which indicates the object is not linked to another one (i.e. it is a top level object). Omit the third argument, link
, to use 'parent_id'
as the default property which links the object to another one by its id
.
const nest = (items, id = null, link = 'parent_id') => items .filter(item => item[link] === id) .map(item => ({ ...item, children: nest(items, item.id) }));
// One top level comment const comments = [ { id: 1, parent_id: null }, { id: 2, parent_id: 1 }, { id: 3, parent_id: 1 }, { id: 4, parent_id: 2 }, { id: 5, parent_id: 4 } ]; const nestedComments = nest(comments); // [{ id: 1, parent_id: null, children: [...] }]
objectFromPairs
Creates an object from the given key-value pairs.
Use Array.prototype.reduce()
to create and combine key-value pairs.
const objectFromPairs = arr => arr.reduce((a, [key, val]) => ((a[key] = val), a), {});
objectFromPairs([['a', 1], ['b', 2]]); // {a: 1, b: 2}
objectToPairs
Creates an array of key-value pair arrays from an object.
Use Object.keys()
and Array.prototype.map()
to iterate over the object's keys and produce an array with key-value pairs.
const objectToPairs = obj => Object.keys(obj).map(k => [k, obj[k]]);
objectToPairs({ a: 1, b: 2 }); // [ ['a', 1], ['b', 2] ]
omit
Omits the key-value pairs corresponding to the given keys from an object.
Use Object.keys(obj)
, Array.prototype.filter()
and Array.prototype.includes()
to remove the provided keys. Use Array.prototype.reduce()
to convert the filtered keys back to an object with the corresponding key-value pairs.
const omit = (obj, arr) => Object.keys(obj) .filter(k => !arr.includes(k)) .reduce((acc, key) => ((acc[key] = obj[key]), acc), {});
omit({ a: 1, b: '2', c: 3 }, ['b']); // { 'a': 1, 'c': 3 }
omitBy
Creates an object composed of the properties the given function returns falsy for. The function is invoked with two arguments: (value, key).
Use Object.keys(obj)
and Array.prototype.filter()
to remove the keys for which fn
returns a truthy value. Use Array.prototype.reduce()
to convert the filtered keys back to an object with the corresponding key-value pairs.
const omitBy = (obj, fn) => Object.keys(obj) .filter(k => !fn(obj[k], k)) .reduce((acc, key) => ((acc[key] = obj[key]), acc), {});
omitBy({ a: 1, b: '2', c: 3 }, x => typeof x === 'number'); // { b: '2' }
orderBy
Returns a sorted array of objects ordered by properties and orders.
Uses Array.prototype.sort()
, Array.prototype.reduce()
on the props
array with a default value of 0
, use array destructuring to swap the properties position depending on the order passed. If no orders
array is passed it sort by 'asc'
by default.
const orderBy = (arr, props, orders) => [...arr].sort((a, b) => props.reduce((acc, prop, i) => { if (acc === 0) { const [p1, p2] = orders && orders[i] === 'desc' ? [b[prop], a[prop]] : [a[prop], b[prop]]; acc = p1 > p2 ? 1 : p1 < p2 ? -1 : 0; } return acc; }, 0) );
const users = [{ name: 'fred', age: 48 }, { name: 'barney', age: 36 }, { name: 'fred', age: 40 }]; orderBy(users, ['name', 'age'], ['asc', 'desc']); // [{name: 'barney', age: 36}, {name: 'fred', age: 48}, {name: 'fred', age: 40}] orderBy(users, ['name', 'age']); // [{name: 'barney', age: 36}, {name: 'fred', age: 40}, {name: 'fred', age: 48}]
pick
Picks the key-value pairs corresponding to the given keys from an object.
Use Array.prototype.reduce()
to convert the filtered/picked keys back to an object with the corresponding key-value pairs if the key exists in the object.
const pick = (obj, arr) => arr.reduce((acc, curr) => (curr in obj && (acc[curr] = obj[curr]), acc), {});
pick({ a: 1, b: '2', c: 3 }, ['a', 'c']); // { 'a': 1, 'c': 3 }
pickBy
Creates an object composed of the properties the given function returns truthy for. The function is invoked with two arguments: (value, key).
Use Object.keys(obj)
and Array.prototype.filter()
to remove the keys for which fn
returns a falsy value. Use Array.prototype.reduce()
to convert the filtered keys back to an object with the corresponding key-value pairs.
const pickBy = (obj, fn) => Object.keys(obj) .filter(k => fn(obj[k], k)) .reduce((acc, key) => ((acc[key] = obj[key]), acc), {});
pickBy({ a: 1, b: '2', c: 3 }, x => typeof x === 'number'); // { 'a': 1, 'c': 3 }
renameKeys
Replaces the names of multiple object keys with the values provided.
Use Object.keys()
in combination with Array.prototype.reduce()
and the spread operator (...
) to get the object's keys and rename them according to keysMap
.
const renameKeys = (keysMap, obj) => Object.keys(obj).reduce( (acc, key) => ({ ...acc, ...{ [keysMap[key] || key]: obj[key] } }), {} );
const obj = { name: 'Bobo', job: 'Front-End Master', shoeSize: 100 }; renameKeys({ name: 'firstName', job: 'passion' }, obj); // { firstName: 'Bobo', passion: 'Front-End Master', shoeSize: 100 }
shallowClone
Creates a shallow clone of an object.
Use Object.assign()
and an empty object ({}
) to create a shallow clone of the original.
const shallowClone = obj => Object.assign({}, obj);
const a = { x: true, y: 1 }; const b = shallowClone(a); // a !== b
size
Get size of arrays, objects or strings.
Get type of val
(array
, object
or string
). Use length
property for arrays. Use length
or size
value if available or number of keys for objects. Use size
of a Blob
object created from val
for strings.
Split strings into array of characters with split('')
and return its length.
const size = val => Array.isArray(val) ? val.length : val && typeof val === 'object' ? val.size || val.length || Object.keys(val).length : typeof val === 'string' ? new Blob([val]).size : 0;
size([1, 2, 3, 4, 5]); // 5 size('size'); // 4 size({ one: 1, two: 2, three: 3 }); // 3
transform
Applies a function against an accumulator and each key in the object (from left to right).
Use Object.keys(obj)
to iterate over each key in the object, Array.prototype.reduce()
to call the apply the specified function against the given accumulator.
const transform = (obj, fn, acc) => Object.keys(obj).reduce((a, k) => fn(a, obj[k], k, obj), acc);
transform( { a: 1, b: 2, c: 1 }, (r, v, k) => { (r[v] || (r[v] = [])).push(k); return r; }, {} ); // { '1': ['a', 'c'], '2': ['b'] }
truthCheckCollection
Checks if the predicate (second argument) is truthy on all elements of a collection (first argument).
Use Array.prototype.every()
to check if each passed object has the specified property and if it returns a truthy value.
const truthCheckCollection = (collection, pre) => collection.every(obj => obj[pre]);
truthCheckCollection([{ user: 'Tinky-Winky', sex: 'male' }, { user: 'Dipsy', sex: 'male' }], 'sex'); // true
unflattenObject
Unflatten an object with the paths for keys.
Use Object.keys(obj)
combined with Array.prototype.reduce()
to convert flattened path node to a leaf node. If the value of a key contains a dot delimiter (.
), use Array.prototype.split('.')
, string transformations and JSON.parse()
to create an object, then Object.assign()
to create the leaf node. Otherwise, add the appropriate key-value pair to the accumulator object.
const unflattenObject = obj => Object.keys(obj).reduce((acc, k) => { if (k.indexOf('.') !== -1) { const keys = k.split('.'); Object.assign( acc, JSON.parse( '{' + keys.map((v, i) => (i !== keys.length - 1 ? `"${v}":{` : `"${v}":`)).join('') + obj[k] + '}'.repeat(keys.length) ) ); } else acc[k] = obj[k]; return acc; }, {});
unflattenObject({ 'a.b.c': 1, d: 1 }); // { a: { b: { c: 1 } }, d: 1 }