hashIt
Fast and consistent hashCode for any object type
Table of contents
Usage
// ES2015
import hashIt from 'hash-it';
// CommonJS
const hashIt = require('hash-it').default;
// script
const hashIt = window.hashIt;
// hash any standard object
console.log(hashIt({foo: 'bar'})); // 2639617176
// or if you know it is a circular object
console.log(hashIt(window, true)); // 482488043
Overview
hashIt
has a simple goal: provide a fast and consistent hashCode for any object type that is uniquely based on its values. This has a number of uses such as duplication prevention or fast equality comparisons.
Any object type?
Yes, any object type. Primitives, ES2015 classes like Symbol
, DOM elements (yes, you can even hash the window
object if you want). Any object type.
With no exceptions?
Well ... sadly, no, there are a few exceptions.
-
Promise
- There is no way to obtain the values contained within due to its asynchronous nature
-
Generator
(the result of calling aGeneratorFunction
)- Like
Promise
, there is no way to obtain the values contained within due to its dynamic iterable nature
- Like
-
WeakMap
/WeakSet
- The spec explicitly forbids iteration over them, so the unique values cannot be discovered
In each of these cases, no matter what the values of the object, they will always yield the same hash result, which is unique to each object type. If you have any ideas about how these can be uniquely hashed, I welcome them!
Here is the list of object classes that have been tested and shown to produce unique hashCodes:
Arguments
Array
ArrayBuffer
Boolean
DataView
Date
(based onvalueOf
)Error
(based onmessage
)- Includes all sub-types (e.g.
TypeError
,ReferenceError
, etc.)
- Includes all sub-types (e.g.
Float32Array
Float64Array
Function
(based ontoString
)GeneratorFunction
(based ontoString
)Int8Array
Int16Array
Int32Array
HTMLElement
(based ontagName
,attributes
, andinnerHTML
)- Includes all sub-types (e.g.
HTMLAnchorElement
,HTMLDivElement
, etc.)
- Includes all sub-types (e.g.
Map
Math
(based onE
,LN2
,LN10
,LOG2E
,LOG10E
,PI
,SQRT1_2
, andSQRT2
)Null
Number
Object
(can handle circular objects)Proxy
RegExp
Set
String
Symbol
Uint8Array
Uint8ClampedArray
Uint16Array
Uint32Array
Undefined
Window
This is basically all I could think of, but if I have missed an object class let me know and I will add it!
Utility functions
isEmpty
isEmpty(object: any): boolean
Determines if object is empty based on hashCode, with empty defined as:
- Empty array (
[]
) - Empty map (
new Map()
) - Empty number, or zero (
0
) - Empty object (
{}
) - Empty set (
new Set()
) - Empty string (
''
) - Undefined (
undefined
) - Null (
null
)
This differs from the implementation by lodash
, where a value is considered not empty if an Array
, Object
, Map
, or Set
. Think of this definition of empty as "having no value(s)".
isEqual
isEqual(object1: any, object2: any[, object3: any[, ...objectN]]): boolean
Compares all objects passed to it to determine if they are equal to one another based on hashCode
const foo = {
foo: 'bar'
};
const alsoFoo = {
foo: 'bar'
};
console.log(foo === alsoFoo); // false
console.log(hashIt.isEqual(foo, alsoFoo)); // true
isNull
isNull(object: any): boolean
Determines if object is null based on hashCode
isUndefined
isUndefined(object: any): boolean
Determines if object is undefined based on hashCode
Gotchas
While the hashes will be consistent when calculated within the same browser environment, there is no guarantee that the hashCode will be the same across different browsers due to browser-specific implementations of features. A vast majority of the time things line up, but there are some edge cases that can cause differences, so just something to be mindful of.
Browser support
- Chrome (all versions)
- Firefox (all versions)
- Edge (all versions)
- Opera 15+
- IE 9+
- Safari 6+
- iOS 8+
- Android 4+
Node support
- 4+
Development
Standard stuff, clone the repo and npm install
dependencies. The npm scripts available:
build
=> run webpack to build developmentdist
file with NODE_ENV=developmentbuild:minified
=> run webpack to build productiondist
file with NODE_ENV=productiondev
=> run webpack dev server to run example app / playgrounddist
=> runsbuild
andbuild:minified
lint
=> run ESLint against all files in thesrc
folderprepublish
=> runsprepublish:compile
when publishingprepublish:compile
=> runlint
,test:coverage
,transpile:es
,transpile:lib
,dist
test
=> run AVA test functions withNODE_ENV=test
test:coverage
=> runtest
but withnyc
for coverage checkertest:watch
=> runtest
, but with persistent watchertranspile:lib
=> run babel against all files insrc
to create files inlib
transpile:es
=> run babel against all files insrc
to create files ines
, preserving ES2015 modules (forpkg.module
)