"Остановка на NaN в JavaScript"
Вопрос: Есть ли современные браузеры, которые вызывают исключения при распространении NaN (например, при умножении или сложении числа с NaN), или такие, которые можно настроить для этой проверки?
Тихое распространение NaN является ужасным и коварным источником ошибок, и я хотел бы иметь возможность выявлять их на ранних стадиях, даже если это повлечет за собой снижение производительности.
Вот пример ошибки, которую нельзя обнаружить с помощью <code>use strict</code>
, <code>jshint</code>
и подобных инструментов:
object = new MyObject();
object.position.x = 0;
object.position.y = 10;
// ... много кода
var newPosition = object.position + 1; // <--- это ошибка, должно быть
// object.position.x
// однако она "молчит" и
// не вызывает никаких ошибок
newPosition *= 2; // <--- здесь тоже нет ошибок.
// этот код в принципе корректен,
// если предыдущая строка была правильной
Примечание: Компилятор TypeScript способен выявлять подобные ошибки, даже в коде JS, если удается провести вывод типов.
5 ответ(ов)
Чтобы ответить на заданный вопрос:
Есть ли современный браузер, который вызывает исключения при распространении NaN (т.е. при умножении или сложении числа с NaN), или который можно настроить на это?
Нет. JavaScript — это очень лояльный язык и не обращает внимания на то, хотите ли вы умножить Math.PI
на 'картошку' (подсказка: это NaN
). Это одна из плохих (или хороших, в зависимости от вашей точки зрения) особенностей языка, с которой разработчикам приходится иметь дело.
Отвечая на ошибку, из-за которой вы задаете этот вопрос (предположительно), использование геттеров и сеттеров в ваших объектах — это один из надежных способов предотвратить подобные ошибки и помочь вам избегать таких ситуаций.
Код ниже может помочь вам.
Чтобы полностью решить эту проблему, нам нужно нечто вроде operator reload
. Мы можем перезагружать операторы, такие как '+', '-', '/', '*', и проверять, является ли операнд числом, если нет — вызывать ошибку.
Как частичное решение, когда JavaScript выполняет операцию, например, 'a + b', он вызовет метод valueOf
, который унаследован от Object.prototype
. Мы можем переписать Object.prototype.valueOf
.
Object.prototype.originalValueOf = Object.prototype.valueOf;
Object.prototype.valueOf = function() {
if (typeof this !== 'number') {
throw new Error('Object is not a Number');
}
return this.originalValueOf();
}
var a = 1 + 2; // -> работает
console.log(a); // -> 3
var b = {};
var c = b + 2; // -> вызовет ошибку
(Подсказка: вы можете удалить код в продакшене и добавить его в вашу среду разработки.)
Самый чистый способ сделать это — создать короткую удобную функцию, которая будет проверять результат выражения каждый раз.
Я понимаю, что это не тот ответ, который вы ищете, но это природа JavaScript, и, увы, вы ничего не можете с этим поделать.
function v(a) {
if (isNaN(a)) throw "ошибка";
return a;
}
var test = v(100 * "abc");
Я знаю, что это старая ветка, но, думаю, у вашего вопроса может быть очень простое решение. Вы можете либо создать функцию для следующего выражения, либо добавить его в код непосредственно.
JavaScript имеет некоторые уникальные особенности для определенных значений. Одно из таких особых поведений касается значения "не число" или NaN
. Значение NaN
не равно никакому другому значению, включая само NaN
. По этой причине следующее выражение:
if(x != x) {
throw "Значение является NaN!";
}
будет истинным только в том случае, если значение x
равно NaN
.
Я думаю, что в этой ситуации удобно использовать геттеры и сеттеры.
Вот пример кода на псевдоязыке, который даст вам общее представление:
// Внутри вашего кода класса Object.
function getPosition() {
// Вы же не хотите, чтобы свойство "position" было NaN, верно?
if(isNaN(this.position))
throw "NaN - это некорректное числовое значение!";
return this.position;
}
// Где-то в вашем коде
var newPosition = object.getPosition() + 1; // вызовет исключение.
Я считаю, что это лучше, чем реализовывать «фейковую» перегрузку операторов и усложнять ситуацию.
Как проверить, является ли число NaN в JavaScript?
Где найти документацию по форматированию даты в JavaScript?
Как проверить, содержит ли массив строку в TypeScript?
Ссылка и выполнение внешнего JavaScript-файла, размещенного на GitHub
Как остановить Babel от трансформации 'this' в 'undefined' и добавления "use strict"