Подтвердить что ты не робот

50 === 50: false. 50 == 50: правда?

У меня полная потеря.

У меня есть функция.

Number.prototype.abs = function () {
    return this >= 0 ? this : this * -1;
};

.., который возвращает абсолютное значение числа.

(50).abs(); // 50
(-50).abs(); // 50

.. но это не сравнится правильно.

(50).abs() === 50; // False

.. иногда.

(50).abs() == 50; // True
(-50).abs() === 50; // True

Дело в том, что он работает в Chrome 12 и Firefox 4, но не в IE 9, Safari 5 или Opera 11.

Я не вижу ничего плохого в коде, и поскольку он работает в Chrome и Firefox, это что-то конкретное для браузера, но я не знаю что.

Обновление: Разница между браузером и поддержкой строгого режима. Я запускаю свой код в строгом режиме, который вводит некоторые изменения, которые заставляют работать мой код. Причина, по которой она не удалась в браузерах, которые она сделала, заключается в том, что они имеют неполный или отсутствующий строгий режим.

Почему он возвращает false?

4b9b3361

Ответ 1

Несмотря на то, что Джереми Хейлер прав, его оправдание неверно истолковано. Почему вы получаете object вместо number не имеет ничего общего с конструкторами.

Проблема заключается в ключевом слове this. Вам нужно понять, что происходит, когда вы используете this. Немного копаться в проекте ECMA покажет вам, что

Это ключевое слово оценивает значение ThisBinding текущего контекста выполнения.

(Я бы изменил выше. Ключевое слово this не оценивает значение , как мы скоро увидим.) Хм, хорошо, но как именно ThisBinding Работа? Читайте дальше!

Следующие шаги выполняются, когда управление входит в контекст выполнения для кода функции, содержащегося в функциональный объект F, предоставленный вызывающий thisArg, и вызывающий argumentsList:

  • Если код функции является строгим кодом, установите значение ThisBinding для этогоArg.
  • Если значение thisArg равно null или undefined, установите значение ThisBinding для глобальный объект.
  • Else, если Type (thisArg) не является объектом, установите для параметра ThisBinding значение   ToObject (thisArg).
  • Else установить значение ThisBinding для этогоArg.
  • Пусть localEnv является результатом вызова NewDeclarativeEnvironment передавая значение [[Область]] внутреннее свойство F как аргумент.
  • Установите для LexicalEnvironment значение localEnv.
  • Задайте переменную окружения localEnv.
  • Пусть код является значением внутреннего свойства Fs [[Code]].
  • Выполнение обязательного связывания с использованием кода функции code и argumentList, как описано в 10.5

И в этом рут (посмотрите на выделенную часть). Если функция вызвана из контекста, отличного от объекта, ThisBinding (aka using this) всегда возвращает значение контекста, заключенного внутри объекта. Самый простой способ исправить это:

Number.prototype.abs = function () {
    "use strict"; // if available
    // * 1 implicitly coerces 'this' to a number value
    return this >= 0 ? this * 1 : this * -1;
    //... or Number(this) explicitly coerces 'this' to its toNumber value
    return Number(this >= 0 ? this : this * -1);
};

... принудить объект this (или принудительный режим). Но я думаю, что важно понять, как работает this, и этот вопрос является отличным примером этого.

Ответ 2

Это связано с тем, что 50 сам по себе является значением Number, тогда как вы возвращаете объект Number.

alert(typeof 50); // number
alert(typeof (50).abs()); // object

http://jsfiddle.net/Pkkaq/

Раздел 4.3.21 Ссылка ECMAScript:

Объект Number создается с помощью конструктор Число в новом выражение, задающее значение Number как аргумент. Полученный объект имеет внутреннее свойство, значение которого это значение Number. Объект Number может быть привязано к значению числа по вызов конструктора Number как функция.

Другими словами, значение Number не может быть строго равно объекту Number.

typeof 50 === typeof new Number(50) //--> false; number != object

Причина, по которой (-50).abs() работает должным образом, состоит в том, что она умножается на -1. Когда объект Number умножается на значение Number, он становится значением Number. В этом случае, если параметр положительный, объект просто возвращается нетронутым, заставляя объект возвращаться.

Вот исправление для вашего метода, в соответствии с приведенной выше ссылкой:

Number.prototype.abs = function () {
    return Number(this >= 0 ? this : this * -1);
};

Ответ 3

Тройка равно (===) проверяет тип, а также значение, чтобы гарантировать, что они равны. Он не работает по той же причине, что new Number(5) !== 5 и new String("Text") !== "Text", поскольку они разные. Однако, когда вы используете свое отрицательное абсолютное значение, вы выполняете математическое вычисление, которое выводит необработанное число, а не числовой объект. В связи с этим проверка типа совпадает, и это правда.

Ответ 4

Math.abs(-50) === 50 работает везде. Поэтому вы можете переписать Number.prototype.abs в:

Number.prototype.abs = function () {
    return Math.abs(this);
};

Я полагаю. Протестировано Math.abs(50) === 50 в IE9 и Chrome 11, оба: true

Другие способы сделать (50).abs() === 50 с помощью вашего метода могут быть:

return this >= 0 ? this.valueOf() : this * -1;
return this >= 0 ? this * 1 : this * -1;

Итак, вы не возвращаете объект (это), когдa > 0, а числовое значение.

Но я бы посоветовал просто использовать уже доступный метод Math.abs, и в этом случае вы можете быть уверены, что Math.abs(50) === 50; возвращает true, и вы избегаете ненужного патч обезьяны.

Для полноты: из выбранного ответа следует, что использование strict также будет решением.

Ответ 5

=== возвращает true, если оба операнда имеют один и тот же ТИП и равны по значению. Я ставлю, что реализации, где он возвращает false, возвращают float вместо int.

Ответ 6

Возникает проблема с вашим методом abs. "this" в вашей функции есть объект, поэтому, когда вы возвращаете "this", это тип объекта. "this" * -1 преобразуется в число с помощью javascript.

Как предполагают люди, использование Math.abs(), вероятно, является лучшим способом.

Если вы действительно хотите, чтобы ваша функция работала, сделайте следующее:

Number.prototype.abs = function () {
    return this >= 0 ? parseInt(this) : this * -1;
};

Конечно, предполагается, что вы работаете только с целыми числами.