Below is a pure function f
for which f(a) !== f(b)
despite a === b
(notice the strict equalities) for some values of a<
In ECMAScript 3, another example where ===
behaves surprisingly is with joined functions. Consider a case like this:
function createConstantFunction(result) {
return function () {
return result;
};
}
var oneReturner = createConstantFunction(1); // a function that always returns 1
var twoReturner = createConstantFunction(2); // a function that always returns 2
An implementation is allowed to "join" the two functions (see §13.2 of the spec), and if it does so, then oneReturner === twoReturner
will be true
(see §13.1.2), even though the two functions do different things. Similarly with these:
// a perfect forwarder: returns a sort of "duplicate" of its argument
function duplicateFunction(f) {
return function (f) {
return f.apply(this, arguments);
};
}
var myAlert = duplicateFunction(alert);
console.myLog = duplicateFunction(console.log);
Here an implementation can say that myAlert === console.myLog
, even though myAlert
is actually equivalent to alert
and console.myLog
is actually equivalent to console.log
.
(However, this aspect of ECMAScript 3 was not preserved in ECMAScript 5: functions are no longer allowed to be joined.)
There are many such functions, here is another example
function f (a) {
return a + 1;
}
1 == "1" but f(1) != f("1")
This is because equality is a nuanced concept.
Perhaps more scary is that in your example -0 === +0.
1/+0
is Infinity and 1/-0
-Infinity, while +0 === -0.
This can be explained by the fact that ECMA defines -0 to equal +0 as a special case, while in other operations these two values retain their different properties, which result in some inconsistencies.
This is only possible because the language explicitly defines two non-equal values to be equal, that in fact are not.
Other examples, if any, should be based on the same sort of artificial equality, and given http://ecma262-5.com/ELS5_HTML.htm#Section_11.9.6 there is no other such excention, so probably no other example of this.
If it's of any use, we can ensure that 0
is not -0
by adding 0
to it:
var f = function(x) {
return 1 / (x + 0);
}
f(+0) === f(-0)
I'm not so sure this is so scary ;-) Javascript is not a pure language and the presence of +/-0 and the equality of -0 and +0 are specific to IEEE-754 and are "well defined", even if perhaps sometimes surprising. (Even NaN != NaN always being true is well defined, for instance.)
From signed zero:
According to the IEEE 754 standard, negative zero and positive zero should compare as equal with the usual (numerical) comparison operators...
Technically, because the two inputs to f
are different, then the result can also be different. For what it's worth, Haskell will treat 0 == -0
as true but will treat (1 / 0) == (1 / (-0))
as false.
However, I do find this an interesting question.
Happy coding.
Yes, because NaN !== NaN
.
var f = function (x) { return Infinity - x; }
Infinity === Infinity // true
f(Infinity) === f(Infinity) // false
f(Infinity) // NaN
Some other examples that yield NaN
whose arguments can be strictly equal:
0/0
Infinity/Infinity
Infinity*0
Math.sqrt(-1)
Math.log(-1)
Math.asin(-2)
this behaviour is perfectly ok, because, in mathematical theory, -0 === +0
is true, and 1/(-0) === 1/(+0)
is not, because -inf != +inf
EDIT: although I am really surprised that javascript can in fact handle these kinds of mathematical concepts.
EDIT2: additionally, the phenomenon you described is completely based on the fact, that you divide by zero from which you should expect at least some strange behaviour.