Pure function given strictly equal arguments yield

2020-03-01 09:05发布

Below is a pure function f for which f(a) !== f(b) despite a === b (notice the strict equalities) for some values of a and b:

var f = function (x) {
   return 1 / x;
}

+0 === -0 // true
f(+0) === f(-0) // false

The existence of such functions can lead to difficult-to-find bugs. Are there other examples I should be weary of?

标签: javascript
6条回答
Explosion°爆炸
2楼-- · 2020-03-01 09:29

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)
查看更多
够拽才男人
3楼-- · 2020-03-01 09:30

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.

查看更多
贼婆χ
4楼-- · 2020-03-01 09:36

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.)

查看更多
孤傲高冷的网名
5楼-- · 2020-03-01 09:37

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.

查看更多
聊天终结者
6楼-- · 2020-03-01 09:38

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)
查看更多
迷人小祖宗
7楼-- · 2020-03-01 09:38

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.

查看更多
登录 后发表回答