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?
Ответы
Ответ 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;
};
Конечно, предполагается, что вы работаете только с целыми числами.