Wondering what’s next for npm?Check out our public roadmap! »

    egal

    1.3.0 • Public • Published

    Egal.js

    NPM version Build status

    Egal.js provides an egal function that tests strict equality (like ===), but adds support for built-in and custom value objects in a type-safe way. It also has a deepEgal function for comparing plain objects and arrays recursively or deeply without giving up on type-safeness on the way. It also handles circular references.

    Tour

    When and why to use egal over the triple-equals === operator?

    • When you need to compare the semantic equivalence of value objects without requiring the same object identity.
      JavaScript's == and === consider two different Date or RegExp objects unequal, even if they mean the same thing.
    • When you need to compare custom value objects in a type-safe way.
      Value objects are objects that have a valueOf function. Egal.js makes sure the two objects with valueOf are actually from the same constructor.
    • When you need to compare objects or arrays recursively, Egal.js has deepEgal.

    Primitives

    A primivitive and its boxed object equivalent are considered different. Allowing unexpected boxed objects (e.g. new Boolean(false)) through is risky as they're extremely error prone (just think of !!new Boolean(false) returning true). Comparing two boxed objects of the same value, on the other hand, will work.

    Objects

    Non-value objects, like Array or Object, are compared by egal as === does it — based on object identity. For recursive or deep comparison, see deepEgal.

    NaN

    NaNs (not-a-number) are not equal (matching how === behaves). This is because when you compare results of two mathematical operations that may both end up as NaN, you might inadvertently assume the calculations went fine. If you expect NaN, you can use JavaScript's built-in isNaN to test for that.

    Zeros

    Negative and positive zeros are equal (also matching how === behaves). You might end up with unexpected negative zeros via various calculations and when you don't need to distinguish between the two, you'll end up with too many false negatives. If you need to handle negative zeros differently, see the article on Sameness in JavaScript.

    Value Objects

    Value objects can also return compound values. That is, you need not return a single primitive value from valueOf, but merely a more primitive one. Those values are compared with deepEgal.

    function Point(x, y) { this.x = x; this.y = y }
    Point.prototype.valueOf = function() { return [this.x, this.y] }
    egal(new Point(42, 69), new Point(42, 69)) // => true
    egal(new Point(42, 69), new Point(13, 42)) // => false

    Installing

    Installing on Node.js

    npm install egal
    

    Installing for the browser

    Egal.js doesn't yet have a build ready for the browser, but you might be able to use Browserify to have it run there till then.

    Using

    Require Egal.js:

    var egal = require("egal")

    Then proceed with comparions:

    egal(42, 42) // => true
    egal(new String("Hello!"), "Hello") // => true
    egal(new Date(2000, 5, 18), new Date(2000, 5, 18)) // => true
    egal(/abc/i, /abc/i) // => true

    Value Objects

    To make and compare custom value objects, create a new constructor and give its prototype a valueOf function:

    function Song(name) { this.name = name }
    Song.prototype.valueOf = function() { return this.name }
     
    egal(new Song("Play Guitar"), new Song("Play Guitar")) // => true
    egal(new Song("Play Guitar"), new Song("Crumblin' Down")) // => false

    Egal.js makes sure the two instances are from the same constructor before comparing their valueOf outputs:

    function Song(name) { this.name = name }
    Song.prototype.valueOf = function() { return this.name }
     
    function Car(name) { this.name = name }
    Car.prototype.valueOf = function() { return this.name }
     
    egal(new Song("KITT"), new Car("KITT")) // => false

    Objects that are instances of a class (their constructor property set to something other than Object) but lack a valueOf function, thereby not being value objects, are compared by reference (===).

    Deep Comparison

    As of v1.1.0, Egal.js comes with a recursive or deep comparison function named deepEgal. It was mostly extracted from the Must.js testing library's eql function.

    var deepEgal = require("egal").deepEgal
    function Model(name) { this.name = name }
     
    deepEgal(42, 42) // => true
    deepEgal({name: "John"}, {name: "John"}) // => true
    deepEgal({stats: {age: 13}}, {{stats: age: 13}}) // => true
    deepEgal([1, 2, 3], [1, 2, 3]) // => true
    deepEgal(new Model("John"), new Model("John")) // => false
    deepEgal(new Date(2000, 5), new Date(2000, 5)) // => true

    The deepEgal function compares regular primitive values, model instances and value objects just like egal.

    Plain objects (those with no custom constructor property in their prototype), are compared recursively by their enumerable properties. Arrays are compared recursively by their contents (iterating over length). See above about value objects for more details on plain, instances and value objects.

    License

    Egal.js is released under a Lesser GNU Affero General Public License, which in summary means:

    • You can use this program for no cost.
    • You can use this program for both personal and commercial reasons.
    • You do not have to share your own program's code which uses this program.
    • You have to share modifications (e.g bug-fixes) you've made to this program.

    For more convoluted language, see the LICENSE file.

    About

    Andri Möll typed this and the code.
    Monday Calendar supported the engineering work.

    If you find Egal.js needs improving, please don't hesitate to type to me now at andri@dot.ee or create an issue online.

    Install

    npm i egal

    DownloadsWeekly Downloads

    6,827

    Version

    1.3.0

    License

    none

    Last publish

    Collaborators

    • avatar