Skip to content

Instantly share code, notes, and snippets.

@uniibu
Created August 5, 2017 18:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save uniibu/49cfd3f8b27464792b1b88f444c0b0c1 to your computer and use it in GitHub Desktop.
Save uniibu/49cfd3f8b27464792b1b88f444c0b0c1 to your computer and use it in GitHub Desktop.
native counterpart of some lodash functions
const assert = require('assert');
/**
* Determines if two values are equal(performs deep comparison).
*
* @param {*} obj The first value to compare from
* @param {*} other The value to compare to
* @return {boolean} True if equal, False otherwise.
*/
const isEqual = (obj, other) => {
try {
if (typeof obj === 'function') {
assert.deepStrictEqual(obj, other);
}
assert.deepEqual(obj, other);
} catch (e) {
return false;
}
return true;
};
/**
* Determines if array.
*
* @param {array} arg The argument
* @return {boolean} True if array, False otherwise.
*/
const isArray = Array.isArray;
/**
* Determines if value is not null and has a type of object
*
* @param {object} value The value
* @return {boolean} True if objectlike, False otherwise.
*/
const isObjectLike = (value) => {
return value !== null && typeof value === 'object';
};
/**
* Determines if value is a string
*
* @param {string} value The value
* @return {boolean} True if string, False otherwise.
*/
const isString = value => {
return !(typeof value !== 'string') || !(value.constructor.name !== 'String');
};
/**
* Returns a function that performs isEqual between a given object and source
*
* @param {object} needle The object of property values to match.
* @return {function} Returns a new spec function
*/
const matches = (needle) => {
return haystack => {
if (needle === haystack) {
return true;
}
return Object.keys(needle).every(key => isEqual(needle[key], haystack[key]));
};
};
/**
* Determines if object and source matches by invoking the customizer to compare values.
*
* @param {object} obj The object to inspect
* @param {object} src The object to match
* @param {(Function)} customizer The function to customize comparisons.
* @return {boolean} True if object is a match, False otherwise.
*/
const isMatchWith = (obj, src, customizer) => {
customizer = typeof customizer === 'function' ? customizer : undefined;
if (!customizer) {
return isEqual(obj, src);
}
return Object.keys(obj).every(key => customizer(obj[key], src[key], key, obj, src));
};
/**
* Flattens an array single-level deep. We could have used Array.concat but it too slow compared
* to lodash's flatten. https://github.com/elidoran/flatten-array
* Note: This mutates the array, to prevent that, wrap it like flatten([array])
*
* @param {array} array The array to flatten
* @return {array} The flattend array
*/
const flatten = array => {
let value;
for (let i = 0; i < array.length;) {
value = array[i];
if (Array.isArray(value)) {
if (value.length > 0) {
value.unshift(i, 1);
array.splice.apply(array, value);
value.splice(0, 2);
} else {
array.splice(i, 1);
}
} else {
i++;
}
}
return array;
};
/**
* Removes falsy values from an array. We could have used Array.filter(Boolean) but again it's
* too slow compared to lodash's compact. https://jsperf.com/remove-falsy-values-from-array
* https://stackoverflow.com/a/16752942
* Note: This mutates the array
*
* @param {array} array The array to inspect
* @return {array} The array with falsy values removed
*/
const compact = array => {
let index = -1,
length = array == null ? 0 : array.length,
resIndex = 0,
result = [];
while (++index < length) {
let value = array[index];
if (value) {
result[resIndex++] = value;
}
}
return result;
};
/**
* Returns the all array values except the first,we could have used
* ([first, ...rest]) => rest; but its again the slowest
* https://jsperf.com/get-tail-of-array
*
* @param {array} The array to inspect
* @return {array} The array with first value removed
*/
const tail = array => {
let index = -1, result = [],
length = array == null ? 0 : array.length + index;
if (length < 1) {
return [];
}
while (++index < length) {
result.push(array[index + 1]);
}
return result;
};
/**
* Capitalized the First letter of a string, and lowercase the rest
*
* @param {string} string The string to inspect
* @return {string} The capitalized string
*/
const capitalize = string => string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
/**
* Returns an object with keys omitted
*
* @param {object} obj The object to inspect
* @param {array|string} keys The key/s to remove from the object
* @return {object} The Object with omitted keys
*/
const omit = (obj, keys) => {
const target = {};
for (const i in obj) {
if (!keys.includes(i)) {
target[i] = obj[i];
}
}
return target;
};
/**
* Returns a new array with only the first occurence of each element is kept
* We could have used Array.from(new Set(arr)) or even new Set(...arr) but
* its too slow compared to lodash's
*
* @param {array} arr The array to inspect
* @return {array} The new array with duplicate removed
*/
const uniq = array => {
let index = -1,
length = array.length,
result = [],
seen = result;
outer:
while (++index < length) {
let value = array[index],
computed = value;
value = value !== 0 ? value : 0;
let seenIndex = seen.length;
while (seenIndex--) {
if (seen[seenIndex] === computed) {
continue outer;
}
}
result.push(value);
}
return result;
};
module.exports = {
isEqual,
isArray,
isObjectLike,
isString,
matches,
isMatchWith,
flatten,
compact,
tail,
capitalize,
omit,
uniq
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment