diff --git a/src/__tests__/keys.js b/src/__tests__/keys.js new file mode 100644 index 0000000..47c8d1a --- /dev/null +++ b/src/__tests__/keys.js @@ -0,0 +1,9 @@ +import keys, { _keys } from '../keys'; + +test('Core.keys', () => { + expect(keys({ a: 1, b: 2 })).toEqual(['a', 'b']); +}); + +test('Internal._keys', () => { + expect(_keys({ a: 1, b: 2 })).toEqual(['a', 'b']); +}); diff --git a/src/index.js b/src/index.js index 546b6fb..5031325 100644 --- a/src/index.js +++ b/src/index.js @@ -23,6 +23,7 @@ import isNumber from './isNumber'; import isObject from './isObject'; import isString from './isString'; import join from './join'; +import keys from './keys'; import last from './last'; import length from './length'; import map from './map'; @@ -64,6 +65,7 @@ export { isObject, isString, join, + keys, last, length, map, diff --git a/src/keys.js b/src/keys.js new file mode 100644 index 0000000..700968d --- /dev/null +++ b/src/keys.js @@ -0,0 +1,45 @@ +/* eslint-disable no-underscore-dangle, no-restricted-syntax */ +import isObject from './isObject'; +import has from './has'; +import length from './length'; +import nth from './nth'; + +export const _keys = obj => { + const hasDontEnumBug = !Object.prototype.propertyIsEnumerable.call( + { toString: null }, + 'toString', + ); + + const dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor', + ]; + + const dontEnumsLength = length(dontEnums); + + if (!isObject(obj)) throw new TypeError('Keys called on non-object'); + + const result = []; + + for (const prop in obj) { + if (has(prop, obj)) result.push(prop); + } + + if (hasDontEnumBug) { + for (let i = 0; i < dontEnumsLength; i++) { + const prop = nth(i, dontEnums); + if (has(prop, obj)) { + result.push(prop); + } + } + } + + return result; +}; + +export default Object.keys || _keys; diff --git a/src/map.js b/src/map.js index e04e865..f64dd83 100644 --- a/src/map.js +++ b/src/map.js @@ -3,13 +3,14 @@ import isObject from './isObject'; import assoc from './assoc'; import append from './append'; import prop from './prop'; +import keys from './keys'; export default (fn, arr) => { if (isObject(arr)) { return reduce( (acc, key) => assoc(key, fn(prop(key, arr)), acc), {}, - Object.keys(arr), + keys(arr), ); }