Underscore: _.isNumber(NaN) 返回真

创建于 2011-12-15  ·  38评论  ·  资料来源: jashkenas/underscore

由于 NaN 代表“非数字”,因此在这种情况下的 isNumber 检查似乎应该返回 false。 我从其他讨论中注意到,这实际上是故意的。 也许文档应该明确反映这一事实。

enhancement fixed

最有用的评论

好的,所以我从一个简单的问题开始。 我的输入是字符串、数字和可能的 NaN。 我在基础 JavaScript 中有一个简单的解决方案,它使用 parseInt 和 isFinite 来测试解析 int 是否成功。 简单但不完全干净或自我描述我的目标。 所以,我决定使用我非常棒的 goto 库来完成这些任务。 我在初始检查时发现一个函数,它说它需要一个值并告诉你它是否是一个数字,根据我的共同定义,我认为这是我想要的。

首先,通过这个你能看到在文档中添加一行将如何帮助库的用户第一次获得正确的工作功能吗? 其次,我再次要求举一个有意义的例子。

听起来你知道关于语言的一切。 因此,与其在我 8 年级的兄弟可以给我的黑暗解决方案中盲目地回击,也许如果您可以通过很棒的文档使用一些掌握的知识来教育我们其他人会更好。 感谢您的时间。

所有38条评论

你说得对,是故意的。 而且我认为不需要明确说明。 以前使用过 IEEE 754 浮点数的任何人都可能知道NaN只是另一个浮点值。

相关:#321 中的讨论

我要问的是,当我执行常见的 Web 任务时,名为 isNumber 的函数似乎是检查找到的值是否满足“这是一个数字?”的常见用户定义的好方法。

此外,在我看来,首先引入 NaN 值是为了帮助识别破坏计算的值。 本着规范的精神,当您问“这是一个数字吗?”这个问题时,这似乎是正确的答案。 事实上,它是“非数字”。 如果你能说出一个常见的例子,你希望这个问题的答案是正确的,我现在就闭嘴:)

您正在寻找isFinite ,了解 JS 的人应该已经知道。

好的,所以我从一个简单的问题开始。 我的输入是字符串、数字和可能的 NaN。 我在基础 JavaScript 中有一个简单的解决方案,它使用 parseInt 和 isFinite 来测试解析 int 是否成功。 简单但不完全干净或自我描述我的目标。 所以,我决定使用我非常棒的 goto 库来完成这些任务。 我在初始检查时发现一个函数,它说它需要一个值并告诉你它是否是一个数字,根据我的共同定义,我认为这是我想要的。

首先,通过这个你能看到在文档中添加一行将如何帮助库的用户第一次获得正确的工作功能吗? 其次,我再次要求举一个有意义的例子。

听起来你知道关于语言的一切。 因此,与其在我 8 年级的兄弟可以给我的黑暗解决方案中盲目地回击,也许如果您可以通过很棒的文档使用一些掌握的知识来教育我们其他人会更好。 感谢您的时间。

我对@jashkenas 的想法很感兴趣。 我的意思不是要听起来侮辱或居高临下。 我知道我有时会这样。 我认为这是一个事实,即我试图通过提供这些简单的答案并看看它们如何未能解决您眼中的问题,将对话引向更好地展示问题的方向。

首先,通过这个你能看到在文档中添加一行将如何帮助库的用户第一次获得正确的工作功能吗?

可能,当然。

其次,我再次要求举一个有意义的例子。

测试 [[Class]] == "Number"? 这应该是显而易见的,它匹配数字。 也许它们不是自然数或整数或有限数或实数或有理数或您期望的任何子集,但它们肯定都是数字。

尽管如此,有时在文档中添加过多的绒毛可能是有害的。 但我不认为这是其中之一。 这对于在当前状态下可能对数字的抽象概念有冲突解释的开发人员可能会有所帮助。 就像在您的情况下一样,您已经为要测试的集合建立了一个心智模型,然后找到了一个_出现_来执行该测试的函数。 +1 ,虽然我仍然对@jashkenas 的想法感兴趣。

是的——当传递NaN时, _.isNumber是否会返回truefalse并不明显。 如果不尝试,我当然不会记得。 在上述提交中的文档中添加了注释。 谢谢。

谢谢你们。 很高兴知道其他人可能不会遇到同样的问题。

这绝对看起来像是语义应该胜过技术事实的情况。 是的,根据某些规范,NaN 可能是一个数字。 但是如果我问一些问题“你是一个数字吗?” 上面写着“我不是数字”,那么我应该相信它。 不是数字 – NaN – 绝对不是数字……并且 isNumber 应该返回 false。

将问题放在文档中——而不是修复一些对人类有意义的东西——只会导致更少的编码时间和更多的时间盯着文档挠你的脑袋。

请问这个可以重新考虑吗?

@contentfree : NaN是浮动的成员。 JS 中的每个数字都是浮点数。 我认为这使得NaN成为他们得到的数字。 NaN并不意味着“我不是一个数字”。 它是非数字的数字表示。 案例在我的书中结案。 如果您想测试不是NaN / Infinity / -Infinity数字,请使用isFinite -Infinity

不是为了打败一匹死马,而是...

为什么不做
obj instanceOf Number

在我看来,如果有一种更具可读性的方式来执行 javascript 规范中已经存在的必要操作,我将这样做,而不是使用带有未知(除非我浪费时间调查)库的库。

我投票认为,如果我们不打算修复这个在语义上是正确的,我们应该从库中删除无用的开销和头痛。

instanceof运算符仅适用于对象,而不适用于原语: new Number(5) instanceof Number == true; 5 instanceof Number == false 。 它也不会跨浏览器中的框架工作。 通过Object::toString [[Class]]检查Object::toString通常被认为是 JavaScript 中最可靠的类型检查方法。

+1 使库更有用,并在同一个实例中教育不熟悉 JavaScript 的用户。

建议:
_.isNumber(object, [isFinite]);

这将允许在发现 isFinite 可能是您最初所追求的时,在遇到此问题时简单地将 true 添加到您当前的实现中。

我的 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-

NaNInfinity _are_ 有效数字。 我认为将这个函数命名为 isValidNumber 会混淆它的目的,或者你的意思是将 isNumber 重命名为 isValidNumber?

NaNInfinity _are_ 有效数字。 我认为将此函数命名为 isValidNumber 会混淆其目的。

我同意。

我没说改名...

我也很惊讶地发现_.isNumber(NaN) === true

我想我倾向于同意@contentfree 的https://github.com/jashkenas/underscore/issues/406#issuecomment -4144992。 在软件工程中,我们甚至有针对这种特定情况的原则

在看到这么多人对此感到困惑之后,我认为让该函数执行非硬核 js 编码人员在查看其名称时期望它执行的操作是有意义的。

只是我的小 2 美分…™

_.isNaN也令人困惑。 在文件中:

注意:这与本机 isNaN 函数不同,它也将为许多其他非数字值返回 true,例如 undefined。

在正常意义上undefined确实是 Not-A-Number。

我投票支持语义建设性, isNumber == Not a number哈哈。 我相信,如果您需要详细了解检查浮点值,那么请以其他方式进行?

我投票支持语义建设性,

不,它是一个由[[Class]] ,就像-InfinityInfinityObject(2) 。 这是开发人员学习的东西之一,就像函数也是对象一样。 您可能希望对您的号码进行某种形式的验证,这超出了此方法的范围。 例如,它是大于-1 、小于Math.pow(2,32)还是整数。 在-InfinityInfinityNaN我使用_.isFinite作为验证器。 类似地, _.isDate不会验证日期对象是否表示有效日期。

使用“另请参阅:isFinite”和“另请参阅:«essay enumerated methods of以确定某事物是否是您可以实际使用的数值»”来更新文档怎么样?

@michaelficarra我知道在规范中 NaN 在很大程度上是一种数字类型。 但是,当程序员问这是一个数字时,他们会这么想吗?

大多数时候,我们大多数人想知道的是,我可以将它用于基本算术吗? 所以你必须去 isNumber(x) && isFinite(x)。 我想这没问题。 但这对新程序员来说是一个很大的问题,而且读起来不太好。

从严格的英语角度来看,从名为 isNumber 的测试返回 true 的 Not a Number (NaN) 完全没有意义。 这不是更好地命名为 isNumeric 或 isNumericType 吗?

我毫不怀疑这会增加错误并浪费很多时间,至少在人们第一次遇到这个问题时。

所以你必须去 isNumber(x) && isFinite(x)。

我最近调整了_.isFinite以遵循 ES6 Number.isFinite
它确保该值是一个数字原语,是有限的,并且应该处理这种常见情况。

无需更改与其他[[Class]]检查方法一致的_.isNumber的行为。

从严格的英语角度来看,从名为 isNumber 的测试返回 true 的 Not a Number (NaN) 完全没有意义。 这不是更好地命名为 isNumeric 或 isNumericType 吗?

请参阅关于验证、 _.isNumber_.isDate

@jdalton您对

但它似乎太违反直觉了,以至于不是数字的东西就是数字。

@Walms 100% 同意。 我认为在这种情况下,程序员和直觉应该否决给定 NaN 是_技术上_数字的语句的绝对“正确性”。

但它似乎太违反直觉了,以至于不是数字的东西就是数字。

在这种情况下,它是否比_.isNumber为数字对象返回true更直观, Object(2)object

这些是[[Class]]方法。 也许需要在文档中更清楚地说明这一点。

我已经提出了一个可行的替代方案,即简单地让_.isFinite跟随 ES6 Number.isFinite 。 如果你想要一个基本的is-number使用typeof x == 'number' 。 如果您想要验证该值不是NaNInfinity-Infinity ,则Number所有[[Class]] Number ,然后_.isFinite是要走的路。

查看underscore-contrib以获得更细粒度的数字方法。 它有_.isNumeric , _.isInteger , _.isZero , _.isEven , _.isOdd , _.isFloat , _.isNegative , & _.isPositive

@jdalton我认为您的最后两条评论确实有助于澄清为什么我认为这令人困惑。

我最初没有看到 _.isNumber 被赋予一个上下文,因为它以 is 为前缀,这意味着它是一个类型检查。 在这种情况下,您是完全正确的,_.isNumber 为 NaN 返回 false 是没有意义的。

但随后 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 这样可笑的东西。 然而,尽管如此狂野和毛茸茸,但 Number 的定义是明确规定的,并且表现始终如一。

另一方面,“数字”是一个定义错误的概念,根据您的谈话对象,它可能包含上述任何内容或不包含任何内容午夜和各种内容。 这很好,但永远不会有一个符合每个人定义的解决方案。

我认为出于这个原因,这本质上是一个文档问题。

对其他人来说,“数字”也不再像一个词了吗?

好点,@sgentle。 我投票支持一致性而不是直觉,因为前者是一个客观的衡量标准,而我们不会就什么是直觉达成一致(如该线程所示)。

只是不要将 NaN 视为“非数字”。 NaN 是一个特殊值。

只是不要将 NaN 视为“非数字”。 NaN 是一个特殊值。

是的,但它被称为“不是数字”。
对我来说就是这样
var _false = "真";
是的,您可以了解到 _false 是真的,但它无缘无故地令人困惑。

@Walms这是一个坏名字,但这不是 JS 的错。 我们可能会责怪将其命名为“NaN”的人。 http://en.wikipedia.org/wiki/NaN

Aargh,我希望_.isNumber(NaN)会返回false ......一些严重的头在这里抓挠,直到我意识到这是原因。

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

@pspi同意。 让_.isNumber()在 _semantic_ 意义上正确运行意味着我永远不会真正使用它。 ._isFinite()似乎是按照我期望的方式工作的函数。

当然,在发布这篇文章的一天后,我发现_.isFinite('1')true ,即使参数不是数字。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

acl0056 picture acl0056  ·  5评论

Francefire picture Francefire  ·  5评论

marcalj picture marcalj  ·  5评论

zackschuster picture zackschuster  ·  5评论

arypbatista picture arypbatista  ·  3评论