0

"Остановка на NaN в JavaScript"

9

Вопрос: Есть ли современные браузеры, которые вызывают исключения при распространении 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 ответ(ов)

0

Чтобы ответить на заданный вопрос:

Есть ли современный браузер, который вызывает исключения при распространении NaN (т.е. при умножении или сложении числа с NaN), или который можно настроить на это?

Нет. JavaScript — это очень лояльный язык и не обращает внимания на то, хотите ли вы умножить Math.PI на 'картошку' (подсказка: это NaN). Это одна из плохих (или хороших, в зависимости от вашей точки зрения) особенностей языка, с которой разработчикам приходится иметь дело.

Отвечая на ошибку, из-за которой вы задаете этот вопрос (предположительно), использование геттеров и сеттеров в ваших объектах — это один из надежных способов предотвратить подобные ошибки и помочь вам избегать таких ситуаций.

0

Код ниже может помочь вам.

Чтобы полностью решить эту проблему, нам нужно нечто вроде 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; // -> вызовет ошибку

(Подсказка: вы можете удалить код в продакшене и добавить его в вашу среду разработки.)

0

Самый чистый способ сделать это — создать короткую удобную функцию, которая будет проверять результат выражения каждый раз.

Я понимаю, что это не тот ответ, который вы ищете, но это природа JavaScript, и, увы, вы ничего не можете с этим поделать.

function v(a) { 
    if (isNaN(a)) throw "ошибка"; 
    return a; 
}

var test = v(100 * "abc");
0

Я знаю, что это старая ветка, но, думаю, у вашего вопроса может быть очень простое решение. Вы можете либо создать функцию для следующего выражения, либо добавить его в код непосредственно.

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

if(x != x) {
    throw "Значение является NaN!";
}

будет истинным только в том случае, если значение x равно NaN.

0

Я думаю, что в этой ситуации удобно использовать геттеры и сеттеры.

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

// Внутри вашего кода класса Object.
function getPosition() {

  // Вы же не хотите, чтобы свойство "position" было NaN, верно?
  if(isNaN(this.position)) 
    throw "NaN - это некорректное числовое значение!";

  return this.position;

}

// Где-то в вашем коде
var newPosition = object.getPosition() + 1; // вызовет исключение.

Я считаю, что это лучше, чем реализовывать «фейковую» перегрузку операторов и усложнять ситуацию.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь