Чистая функция дает строго равные аргументы, дающие не строго равные результаты
Ниже чистая функция f
, для которой f(a) !== f(b)
, несмотря на a === b
(обратите внимание на строгие равенства) для некоторых значений a
и b
:
var f = function (x) {
return 1 / x;
}
+0 === -0 // true
f(+0) === f(-0) // false
Существование таких функций может привести к труднодоступным ошибкам. Есть ли другие примеры, которые я должен утомлять?
Ответы
Ответ 1
Да, потому что 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)
Ответ 2
это поведение вполне нормально, потому что в математической теории -0 === +0
истинно, а 1/(-0) === 1/(+0)
нет, потому что -inf != +inf
EDIT: хотя я действительно удивлен тем, что javascript действительно может обрабатывать эти виды математических понятий.
EDIT2: кроме того, описанное вами явление полностью основано на том факте, что вы разделите на нуль, из которого вы должны ожидать хотя бы какого-то странного поведения.
Ответ 3
1/+0
- бесконечность и 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)
Ответ 4
В 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: функции больше не допускаются к объединению.)
Ответ 5
Я не уверен, что это так страшно;-) Javascript - это не чистый язык и наличие +/- 0, а равенство -0 и +0 специфичны для IEEE-754 и "хорошо определены", даже если, возможно, иногда это удивительно. (Даже NaN!= NaN, всегда являющееся истинным, хорошо определено, например.)
От подписанный нуль:
В соответствии со стандартом IEEE 754 отрицательный нуль и положительный ноль должны сравниваться как с обычными (численными) операторами сравнения...
Технически, поскольку два входа в f
различны, тогда результат также может быть другим. Для чего он стоит, Haskell будет относить 0 == -0
как истинный, но будет относиться к (1 / 0) == (1 / (-0))
как false.
Однако я нахожу этот интересный вопрос.
Счастливое кодирование.
Ответ 6
Существует много таких функций, вот еще один пример
function f (a) {
return a + 1;
}
1 == "1"
но f (1)!= f ( "1" )
Это потому, что равенство - это тонкая концепция.
Возможно, более страшно, чем в вашем примере -0 === +0.