An extension of the "same-value" algorithm as [described for use by ES6 Map
and Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Key_equality)

NaN is considered the same as NaN, however -0 and 0 are considered the same
value, which is different from the algorithm described by
[`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is).

This is extended further to allow Objects to describe the values they
represent, by way of `valueOf` or `equals` (and `hashCode`).

Note: because of this extension, the key equality of Immutable.Map and the
value equality of Immutable.Set will differ from ES6 Map and Set.

### Defining custom values

The easiest way to describe the value an object represents is by implementing
`valueOf`. For example, `Date` represents a value by returning a unix
timestamp for `valueOf`:

var date1 = new Date(1234567890000); // Fri Feb 13 2009 ...
var date2 = new Date(1234567890000);
date1.valueOf(); // 1234567890000
assert( date1 !== date2 );
assert( Immutable.is( date1, date2 ) );

Note: overriding `valueOf` may have other implications if you use this object
where JavaScript expects a primitive, such as implicit string coercion.

For more complex types, especially collections, implementing `valueOf` may
not be performant. An alternative is to implement `equals` and `hashCode`.

`equals` takes another object, presumably of similar type, and returns true
if the it is equal. Equality is symmetrical, so the same result should be
returned if this and the argument are flipped.

assert( a.equals(b) === b.equals(a) );

`hashCode` returns a 32bit integer number representing the object which will
be used to determine how to store the value object in a Map or Set. You must
provide both or neither methods, one must not exist without the other.

Also, an important relationship between these methods must be upheld: if two
values are equal, they *must* return the same hashCode. If the values are not
equal, they might have the same hashCode; this is called a hash collision,
and while undesirable for performance reasons, it is acceptable.

if (a.equals(b)) {
assert( a.hashCode() === b.hashCode() );
}

All Immutable collections implement `equals` and `hashCode`.
function is(valueA, valueB) {
	    if (valueA === valueB || (valueA !== valueA && valueB !== valueB)) {
	      return true;
	    }
	    if (!valueA || !valueB) {
	      return false;
	    }
	    if (typeof valueA.valueOf === 'function' &&
	        typeof valueB.valueOf === 'function') {
	      valueA = valueA.valueOf();
	      valueB = valueB.valueOf();
	      if (valueA === valueB || (valueA !== valueA && valueB !== valueB)) {
	        return true;
	      }
	      if (!valueA || !valueB) {
	        return false;
	      }
	    }
	    if (typeof valueA.equals === 'function' &&
	        typeof valueB.equals === 'function' &&
	        valueA.equals(valueB)) {
	      return true;
	    }
	    return false;
	  }