Underscore: _.isNumber (NaN) возвращает истину

Созданный на 15 дек. 2011  ·  38Комментарии  ·  Источник: jashkenas/underscore

Поскольку NaN означает «Not a Number», проверка isNumber в этом случае должна возвращать false. Я заметил из других дискуссий, что это на самом деле сделано намеренно. Возможно, документация должна явно отразить этот факт.

enhancement fixed

Самый полезный комментарий

Итак, я начал с простой задачи. У меня есть входные данные - строки, числа и, возможно, NaN. У меня есть простое решение в базовом JavaScript, использующее parseInt и isFinite для проверки успешности синтаксического анализа int. Простой, но не полностью чистый и не описывающий мою цель. Итак, я решил использовать мою потрясающую библиотеку goto для выполнения подобных задач. Я нахожу функцию при первоначальной проверке, которая говорит, что принимает значение и сообщает вам, является ли это числом, что, по моему общему определению, является тем, что я думаю, что я хочу.

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

Похоже, вы знаете все, что нужно знать о языке. Так что, вместо того, чтобы извергать слепой выстрел в темноте решения, которые мог бы дать мне мой брат из 8-го класса, может быть, было бы неплохо, если бы вы могли использовать часть этого мастерства, обучая остальных из нас с помощью потрясающей документации. Спасибо за уделенное время.

Все 38 Комментарий

Вы правы, это специально. И я не думаю, что это нужно явно указывать. Любой, кто когда-либо работал с IEEE 754 с плавающей запятой, вероятно, знает, что NaN - это просто еще одно значение с плавающей запятой.

По теме: обсуждение в # 321

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

Кроме того, мне кажется, что значение NaN было введено в первую очередь, чтобы помочь идентифицировать значения, которые нарушают вычисления. В духе спецификации это кажется правильным ответом, когда вы задаете вопрос "это число?" на самом деле это «не число». Если вы можете назвать общий пример, в котором вы хотите, чтобы ответ на этот вопрос был верным, я сейчас молчу :)

Вы ищете isFinite , о котором люди, знающие JS, уже должны знать.

Итак, я начал с простой задачи. У меня есть входные данные - строки, числа и, возможно, NaN. У меня есть простое решение в базовом JavaScript, использующее parseInt и isFinite для проверки успешности синтаксического анализа int. Простой, но не полностью чистый и не описывающий мою цель. Итак, я решил использовать мою потрясающую библиотеку goto для выполнения подобных задач. Я нахожу функцию при первоначальной проверке, которая говорит, что принимает значение и сообщает вам, является ли это числом, что, по моему общему определению, является тем, что я думаю, что я хочу.

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

Похоже, вы знаете все, что нужно знать о языке. Так что, вместо того, чтобы извергать слепой выстрел в темноте решения, которые мог бы дать мне мой брат из 8-го класса, может быть, было бы неплохо, если бы вы могли использовать часть этого мастерства, обучая остальных из нас с помощью потрясающей документации. Спасибо за уделенное время.

Мне интересно, что думает @jashkenas . Я не хочу показаться оскорбительным или снисходительным. Я знаю, что иногда так бываю. Я думаю, дело в том, что я пытаюсь направить разговор в направлении, которое лучше демонстрирует проблему, давая эти простые ответы и видя, как они не могут решить проблему в ваших глазах.

Во-первых, вы видите, как добавление строки в документацию поможет пользователям библиотеки получить нужную функцию для работы с первого раза?

Возможно, конечно.

Во-вторых, я снова прошу привести пример, в котором это имеет смысл.

Тестирование на [[Class]] == "Number"? Это должно быть очевидно, это соответствует числам. Может быть, это не натуральные или целые числа, или конечные числа, или действительные числа, или рациональные числа, или любое другое подмножество, которое вы ожидали, но все они, безусловно, являются числами.

Тем не менее, бывают случаи, когда добавление слишком большого количества пустяков в документацию может быть вредным. Но я не думаю, что это один из тех случаев. Это потенциально может быть полезно для разработчиков, которые в своем текущем состоянии могут иметь противоречивую интерпретацию абстрактного понятия числа. Как и в вашем случае, где вы уже создали мысленную модель набора, для которого вы хотите протестировать, а затем нашли функцию, которая _ появилась_ для выполнения этого теста. +1 , хотя мне все еще интересно, что думает @jashkenas .

Да - совсем не очевидно, вернет ли _.isNumber true или false при передаче NaN . Я бы точно не вспомнил, если бы не попробовал. Добавлено примечание к документации в приведенном выше коммите. Спасибо.

Спасибо ребята. Приятно знать, что кто-то другой может не столкнуться с этой же проблемой.

Это определенно похоже на тот случай, когда семантика должна преобладать над техническими фактами. Да, NaN может быть числом в соответствии с некоторыми спецификациями. Но если я что-то задаю вопрос «Вы номер?» и там написано: «Я не число», тогда я должен этому верить. Not a Number - NaN - определенно не является числом ... и isNumber должен возвращать false.

Помещение Gotcha в документацию - вместо того, чтобы исправлять вещи, чтобы они имели смысл для людей - просто приводит к тому, что меньше времени уделяется кодированию и больше времени просматривается в документации, ломающей голову.

Можно ли это пересмотреть?

@contentfree : NaN является членом числа с плавающей запятой. Каждое число в JS - это число с плавающей запятой. Я думаю, это делает NaN таким же количеством, как и они. NaN не означает «Я не число». Это числовое представление нечисловых. Дело закрыто в моей книге. Используйте isFinite если вы хотите проверить числа, отличные от NaN / Infinity / -Infinity .

Не бить дохлую лошадь, а ...

Почему бы просто не сделать
obj instanceOf Number

Мне кажется, что если есть более читаемый способ выполнения необходимого действия, который уже существует в спецификации javascript, я собираюсь сделать это таким образом, не используя библиотеку с неизвестной (если я не трачу время на исследование) библиотекой.

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

Оператор instanceof будет работать только для объектов, но не для примитивов: new Number(5) instanceof Number == true; 5 instanceof Number == false . Он также не будет работать во фреймах в браузерах. [[Class]] проверка с помощью Object::toString обычно считается наиболее надежным методом проверки типов в JavaScript.

+1 о том, как сделать библиотеку более полезной и в то же время обучить пользователей, плохо знакомых с JavaScript.

Предположение:
_.isNumber (объект, [isFinite]);

Это позволит просто добавить true в вашу текущую реализацию, когда поймете эту ошибку, пока вы узнаете, что isFinite, вероятно, было тем, что вы искали в первую очередь.

Мой 2c

@ nickl - Интересная идея, но ... почему бы в таком случае просто не использовать isFinite ?

В качестве альтернативы, поскольку _.isNaN уже существует, _.isFinite потенциально может быть добавлено для симметрии:

_.isFinite = function (value) {
  return value > -1 / 0 && value < 1 / 0;
};

@kitcambridge

Единственная проблема, которую я предвижу в этом отношении, заключается в том, что строки будут передаваться как конечные «0x0», «0xF», «2» и т. Д. Так что, несмотря ни на что, его нужно будет объединить с _.isNumber или его эквивалентом:

_.isFinite = function (obj) {
  return obj > -1/0 && obj < 1/0 && _.isNumber(obj);
};

Можно сократить пять символов, используя val === + val для проверки чисел:

_.isFinite = function (obj) {
  return obj > -1/0 && obj < 1/0 && obj === +obj;
};

@octatone Конечно, я думаю, что это справедливо ... технически эти строки _are_ конечные, поскольку их можно использовать в числовых сравнениях (интерпретатор должен принуждать их к числам), но ваше предложение более согласуется с существующими функциями проверки типа Underscore.

А как насчет _, isValidNumber, который встроен в существующий _.isValidDate и не сбивает с толку аргумент isFinite?

@ nickl-

NaN и Infinity _are_ допустимые числа. Я думаю, что присвоение этой функции имени isValidNumber запутает ее назначение или вы имеете в виду переименование isNumber в isValidNumber?

NaN и Infinity _are_ допустимые числа. Я думаю, что присвоение этой функции имени isValidNumber сбивает с толку ее назначение.

Я согласен.

Я не сказал переименовать ...

Я тоже был удивлен, узнав, что _.isNumber(NaN) === true .

Думаю, я склонен согласиться с https://github.com/jashkenas/underscore/issues/406#issuecomment -4144992 @ contentfree. В разработке программного обеспечения у нас даже есть принцип для этого конкретного случая: принцип наименьшего удивления . ;-)

И после того, как многие люди запутались в этом, я думаю, что имеет смысл заставить функцию делать то, что люди, не являющиеся hard-core-js-coders, ожидают от нее, когда они смотрят на ее имя.

Просто мои маленькие 2 ¢… ™

_.isNaN тоже сбивает с толку. В документе:

Примечание: это не то же самое, что собственная функция isNaN, которая также возвращает истину для многих других нечисловых значений, таких как undefined.

в нормальном смысле undefined действительно не является числом.

Голосую за семантическую конструктивность, isNumber == Not a number lol. Я считаю, что если вам нужно подробно рассказать о проверке значений с плавающей запятой, то сделайте это другим способом?

Голосую за смысловую конструктивность,

Нет, это число от [[Class]] точно так же, как -Infinity , Infinity , & Object(2) . Это одна из тех вещей, которые изучают разработчики, подобно тому, как функции тоже являются объектами. Скорее всего, вы захотите выполнить некоторую форму проверки вашего номера, которая выходит за рамки этого метода. Например, оно больше -1 , меньше Math.pow(2,32) или целое число. В случаях -Infinity , Infinity или NaN я использую _.isFinite в качестве валидатора. Точно так же _.isDate не проверяет, представляет ли объект даты действительную дату.

Как насчет обновления документации с помощью «см. Также: isFinite» и «см. Также:« эссе перечисление методов определения того, является ли что-то числовым значением, которое вы действительно можете использовать »»

@michaelficarra Я знаю, что в спецификации NaN - это числовой тип. Но не об этом ли думает программист, когда спрашивает, является ли это числом?

Чаще всего большинство из нас хочет знать, могу ли я использовать это для базовой арифметики. Итак, вам нужно пойти isNumber (x) && isFinite (x). Думаю, это нормально. Но это большая проблема для начинающего программиста, и она плохо читается.

С точки зрения строго английского языка, Not a Number (NaN), возвращающий true из теста isNumber, вообще не имеет смысла. Разве его не лучше назвать isNumeric или isNumericType?

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

Итак, вам нужно пойти isNumber (x) && isFinite (x).

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

Нет необходимости изменять поведение _.isNumber которое соответствует другим методам проверки [[Class]] .

С точки зрения строго английского языка, Not a Number (NaN), возвращающий true из теста isNumber, вообще не имеет смысла. Разве его не лучше назвать isNumeric или isNumericType?

См. Мой комментарий о проверке, _.isNumber и _.isDate .

@jdalton Вы

Но это кажется настолько нелогичным, что то, что называется не числом, является числом.

@Walms на 100% согласен. Я думаю, что в этом случае программист и интуиция должны отвергнуть абсолютную «правильность» утверждения, что NaN является _техническим_ числовым.

Но это кажется настолько нелогичным, что то, что называется не числом, является числом.

В этом контексте является ли он более интуитивным, чем _.isNumber возвращающий true для числовых объектов, Object(2) которые относятся к типу object ?

Это [[Class]] методы. Может быть, это нужно прояснить в документации.

Я уже предложил жизнеспособную альтернативу: просто заставить _.isFinite следовать за ES6 Number.isFinite . Если вам нужен базовый is-number используйте typeof x == 'number' . Если вам нужна некоторая проверка того, что значение не NaN , Infinity или -Infinity , все [[Class]] из Number , тогда _.isFinite - это то, что вам нужно.

Посмотрите на underscore-contrib для более точных числовых методов. В нем есть _.isNumeric , _.isInteger , _.isZero , _.isEven , _.isOdd , _.isFloat , _.isNegative , & _.isPositive .

@jdalton Я думаю, что последние два комментария действительно помогли прояснить, почему я думаю, что это сбивает с толку.

Первоначально я не видел, чтобы _.isNumber был задан контекстом из-за того, что перед ним был префикс is, что означает, что это была проверка типа. В этом контексте вы полностью правы, для _.isNumber нет смысла возвращать false для NaN.

Но тогда underscore-contrib и isFinite, похоже, нарушают этот контекст. Они начинают с «есть», но при этом смотрят на значение, а не на тип. И здесь я думаю, что путаница заключается в том, что нет четкого способа определения контекста по имени функции.

Все это говорит о том, что я не вижу способа исправить это.

Я думаю, что проблема здесь в том, что в Numbers есть некоторые вещи, которые не интуитивно понятны. Тем не менее, они ведут себя последовательным образом. В этом случае можно было бы сделать _.isNumber более интуитивным, сделав его менее согласованным, что в конечном итоге сделало бы его менее интуитивным в других случаях.

Вот несколько конкретных примеров:

# If you add two Numbers together you always get another Number back
# This function should always return true no matter what you pass it
closedUnderAddition = (a, b) -> !isNumber(a) || !isNumber(b) || isNumber(a + b)

closedUnderAddition(1,1) == true
closedUnderAddition(Number.MAX_INT,2**970) == true # false if isNumber checks finiteness

# If you divide two Numbers you always get another Number back
closedUnderDivision = (a, b) -> !isNumber(a) || !isNumber(b) || isNumber(a / b)

closedUnderDivision(1, 2) == true
closedUnderDivision(1, 0) == true # false if isNumber checks finiteness
closedUnderDivision(0, 0) == true # false if isNumber checks finiteness or NaN-ness

# Anything you cast to a Number is a Number
castsToNumber = (x) -> isNumber(Number(x))

castsToNumber(1) == true
castsToNumber(Infinity) == true # false if isNumber checks finiteness
castsToNumber("bees") == true # false if isNumber checks finiteness or NaN-ness
castsToNumber("3") == true

Как сказал Михаэльфикарра:

NaN не означает «Я не число». Это числовое представление нечисловых.

Или, иначе говоря, есть «числа» и «числа». NaN может и не быть «числом», но это абсолютно число вместе с бесконечностью, бесконечностью и такими нелепыми вещами, как -0. Каким бы диким и пушистым оно ни было, определение числа четко определено и ведет себя последовательно.

«число», с другой стороны, - это плохо определенная концепция, которая, в зависимости от того, с кем вы разговариваете, может включать в себя любое или ничего из вышеперечисленного , а также, возможно, числовые строки, логические значения, полночь и всевозможные вещи. Это нормально, но никогда не будет решения, которое бы соответствовало всем определениям.

Я думаю, что по этой причине это, по сути, проблема с документацией.

Кроме того, «число» перестало быть словом для кого-то еще?

Хорошие моменты, @sgentle. Я голосую за последовательность, а не за интуитивность, поскольку первая является объективной мерой, в то время как мы не все согласны с тем, что интуитивно понятно (как демонстрирует эта ветка).

Только не относитесь к NaN как к «не числу». NaN - это особое значение.

Только не относитесь к NaN как к «не числу». NaN - это особое значение.

Да, но это называется «Не число».
Для меня это так
var _false = "истина";
Да, вы можете узнать, что _false - это правда, но это сбивает с толку без уважительной причины.

@Walms Это плохая http://en.wikipedia.org/wiki/NaN

Aargh, я хочу _.isNumber(NaN) будет вернуть false ... некоторые серьезные царапины на голове здесь , пока я не понял , что это было причиной.

if (isNaN(Number(value))) {
  alert('Number required.');
}

@pspi Согласен. Заставить _.isNumber() вести себя правильно в _семантическом_ смысле означает, что я никогда не буду его использовать. ._isFinite() кажется функцией, которая работает так, как я ожидал.

И, конечно же, через день после публикации я обнаружил, что _.isFinite('1') - это true , хотя аргумент не является числом.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги