给出严格相等参数的纯函数产生非严格相等的结果

Pure function given strictly equal arguments yielding non-strictly equal results

本文关键字:结果 参数 函数      更新时间:2023-09-26

下面是一个纯函数f,尽管a === b(注意严格的等式)对ab的某些值f(a) !== f(b):

var f = function (x) {
   return 1 / x;
}
+0 === -0 // true
f(+0) === f(-0) // false

这些函数的存在会导致难以发现的bug。还有其他我应该厌倦的例子吗?

是的,因为NaN !== NaN .

var f = function (x) { return Infinity - x; }
Infinity === Infinity // true
f(Infinity) === f(Infinity) // false
f(Infinity) // NaN

其他产生NaN的例子,其参数可以严格相等:

0/0
Infinity/Infinity
Infinity*0
Math.sqrt(-1)
Math.log(-1)
Math.asin(-2)

这种行为是完全可以的,因为在数学理论中,-0 === +0是正确的,而1/(-0) === 1/(+0)不是,因为-inf != +inf

编辑:虽然我真的很惊讶javascript实际上可以处理这些数学概念。

EDIT2:另外,你所描述的现象完全是基于这样一个事实,你除以零,你应该期待至少一些奇怪的行为。

1/+0为Infinity, 1/-0为-Infinity,而+0 === -0。

这可以通过以下事实来解释:ECMA将-0定义为特殊情况下等于+0,而在其他操作中,这两个值保留其不同的属性,从而导致一些不一致。

这是唯一可能的,因为语言显式地将两个不相等的值定义为相等,而实际上不是。

其他的例子,如果有的话,应该基于同样的人为平等,并且给出http://ecma262-5.com/ELS5_HTML.htm#Section_11.9.6,没有其他这样的例外,所以可能没有其他的例子。

如果它有任何用处,我们可以通过添加0来确保0不是-0:

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

在ECMAScript 3中,另一个===行为令人惊讶的例子是与连接的函数。考虑这样一个情况:

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

允许实现"连接"两个函数(参见规范的13.2节),如果这样做,那么oneReturner === twoReturner将是true(参见13.1.2节),即使这两个函数做不同的事情。类似地:

// 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);

这里的实现可以说是myAlert === console.myLog,尽管myAlert实际上相当于alert, console.myLog实际上相当于console.log

(然而,ECMAScript 3的这方面在ECMAScript 5中没有保留:函数不再被允许连接)

我不太确定这是所以可怕;-)Javascript不是一种纯粹的语言,+/-0的存在以及-0和+0的相等性是特定于IEEE-754的,并且是"定义良好的",即使有时可能令人惊讶。(例如,即使NaN != NaN总是为真也是定义良好的。)

From signed 0:

根据IEEE 754标准,负零和正零应该用通常的(数值)比较运算符进行相等的比较…

从技术上讲,由于f 的两个输入不同,那么结果也可能不同。无论如何,Haskell会将0 == -0视为真值,而将(1 / 0) == (1 / (-0))视为假值。

然而,我确实发现这是一个有趣的问题。

快乐编码。

有很多这样的函数,下面是另一个例子

function f (a) {
  return a + 1;
}

1 == "1"但是f(1) != f("1")

这是因为平等是一个微妙的概念。

也许更可怕的是在你的例子中-0 === +0。