Most JavaScript programmers are aware that “normal” equality (==) should be avoided in favor of strict equality (===) [1]. However, every now and then you need something even stricter than ===: If you want to check for NaN or if you want to distinguish between -0 and +0. This blog post explains the details and ECMAScript.next’s [2] solution, the “is” operator.
Checking for NaN
NaN is not strictly equal to itself, breaking the fundamental law of reflexivity: In mathematics, any value x is always equal to itself:x = xThat law doesn’t hold for === and NaN:
> NaN === NaN
false
As a consequence, you can’t find NaN in arrays via indexOf, because that method relies on === to determine which array elements are equal to its first argument:
> [ NaN ].indexOf(NaN)
-1
If you can’t use === to check for NaN, what is the alternative? There is the global function isNaN(), but it is problematic, because it converts its argument to number and thus returns true for many values that clearly are not NaN [3]:
> isNaN("foo")
true
Explanation: "foo" converted to number is NaN.
> Number("foo")
NaN
One way to detect NaN is to exploit the fact that it is the only value that isn’t strictly equal to itself:
function myIsNaN(value) {
return value !== value;
}
A more self-explanatory alternative is to use isNaN() after checking whether the value is a number. This avoids the problematic conversion of non-numbers [3].
function myIsNaN2(value) {
return typeof value === 'number' && isNaN(value);
}
ECMAScript.next will have Number.isNaN(), a fixed version of the global isNaN().
Distinguishing between -0 and +0
This use case is rare, but sometimes you might want to distinguish between -0 and +0 – which are distinct values in JavaScript. === does not let you do that:
> -0 === +0
true
How can you make the distinction? It turns out that you can divide by zero in JavaScript. If the number is positive and you divide it by −0, the result is -Infinity. If you divide it by +0, the result is Infinity. Conveniently, the two infinities can be distinguished by ===:
> 1 / -0
-Infinity
> 1 / +0
Infinity
> Infinity === -Infinity
false
Stricter equality in ECMAScript.next: the “is” operator
ECMAScript.next will have an “is” operator that performs “stricter equality”: It considers NaN equal to itself and distinguishes between -0 and +0. Its negation is called “isnt”. Examples:
> NaN is NaN
true
> -0 isnt +0
true
The operator is complemented by a function Object.is() that can be back-ported to older versions of ECMAScript. On those versions, it could be implemented as follows (a slightly edited version of the ECMAScript.next proposal):
Object.is = function(x, y) {
if (x === y) {
// x === 0 => compare via infinity trick
return x !== 0 || (1/x === 1/y);
}
// x !== y => return true only if both x and y are NaN
return x !== x && y !== y;
};
Why does the ECMAScript.next proposal use the name “egal”?
The reason that the ECMAScript.next proposal uses the name “egal” for the “is” operator is due to the seminal paper on equality, “Equal Rights for Functional Objects or, The More Things Change, The More They Are the Same” by Henry G. Baker, 1990. Quoting that paper’s explanation for calling its equality operator “egal”:Egal is the obsolete Norman term for equal, and Égalité is the French word for social equality.
10 comments:
Can you please give an idea about the use case of distinguishing between +0 and -0?
It’s usually better not to worry about the difference and to consider them one and the same. The difference usually doesn’t matter. There are a few instances, where it does matter, e.g. some Math.* functions (more in an upcoming blog post).
"egal" for equality seems a little weird for a german-speaking person ;)
Still one thing is coming in my mind, whether it would be appropriate in supposing that if no type transformation arises, there would be a little efficiency obtain over == operators.
Where did you find out about the egal pieces of the ES.next spec? In other words, what source are you quoting?
Indeed. Even in French, égal is more synonymous to “don’t care”, these days.
Possible. It could be a tiny bit faster than ===.
The spec refers to the paper that I’m quoting.
This is getting ridiculous. Can we please start removing stupid parts of the language instead of adding more.
And "égal" is the French translation of English "equals" (because old Norman quite often matches modern French ;)
Moreover "Egalité" is also used in French for mathematical equality, not only social equality.
Post a Comment