【问题标题】:What does a + prefix do in this context?+ 前缀在这种情况下有什么作用?
【发布时间】:2013-02-26 00:10:59
【问题描述】:

这是来自underscore 的一行代码。这一行的加号前缀是什么?

if (obj.length === +obj.length) { // plus prefix?

【问题讨论】:

  • 转换为数字。
  • 我不知道您在哪里找到该代码,但 breaker 永远不会起作用。看起来它的意图是迭代器函数可以返回一个空对象以指示它是时候返回了,但它不可避免地会返回一个 不同 的空对象,因为“breaker”是该函数的本地对象.
  • @pure_code no,+ 前缀 converts 为数字,因此该测试确保“obj”是一个类似数组的对象并且它的“长度”属性是一个数字。

标签: javascript


【解决方案1】:

添加+ 符号可以有效地将变量转换为数字,这样:

+"1" === 1;

但是,请注意

+"1" === "1"; // FALSE
+"1" ==  "1"; // TRUE

这是因为== 会将其操作数转换为相同的类型,而=== 不会。

这意味着测试:

obj.length === +obj.length

本质上是在尝试测试obj.length 是否为数字。

在 Underscore 中,此代码试图确定未知类型的变量是否具有名为 length 的属性以及它是否为数字。假设是,如果这两个都是真的,你可以迭代变量是如果它是一个数组。

编辑

请注意,OP 的代码中有许多错误,其中最重要的是这种检测某事物是否为数组(或类似数组)的方法。以下对象会导致问题:

var footballField = {
    covering: "astroturf",
    condition: "muddy",
    length: 100
};

我不是在提倡上述方法...只是解释别人的方法。

【讨论】:

  • 因为Object 可以有一个length 属性,可以是任何东西。
  • @pure_code:发挥你的想象力。 {length:"I'm clearly not a number"}
  • 检查数字 length 属性是不是好的做法... OP 提供的代码 sn-p 有许多错误,这是一个其中。
  • @Dancrumb:这既不是好的做法也不是坏的做法。需要有一些 标准来确定一个对象是否是“类数组”,因此可以迭代。这是他们选择的标准。如果他们没有阅读文档是用户的错,因此传递了一个他们不应该传递的对象。
  • 好吧,如果库的文档说:“适用于任何对象,只要该对象不具有称为 'length' 的属性,不管它是否有意义”,我' d 认为它是一个质量很差的库。
【解决方案2】:

加号前缀将变量转换为数字。基本上,obj.length === +obj.length 是对 obj.length 确实是一个数字的健全性检查。如果obj.length 不是数字,例如字符串"foo",则"foo" === +"foo" 将等同于假,因为+"foo" 的输出为NaN

【讨论】:

    【解决方案3】:

    这会强制 obj.length 的值为 Number。本质上,这样做是为了确保类数组对象的默认 length 值没有被覆盖,以便可以正确迭代。

    breaker 在这种情况下不会做任何事情,因为即使是另一个空对象 {}breaker 相比也会评估为 false .. 即使没有等价比较。

    但是,breaker 没有在该上下文中使用,因为它是在.each 函数外部定义的,这看起来与您在此处显示的不同。相反,它用于从其他循环方法中强制“中断”:

    _.every = _.all = function(obj, iterator, context) {
      /* snip */
      if (!(result = result && iterator.call(context, value, index, list)))
          return breaker;
    

    你可以看到,如果“every”中的结果不是真的,我们想立即中断。 _.every 调用 _.each,它会返回 breaker,与它自身相比,这将是真的,允许立即中断。

    【讨论】:

    • @pure_code 如果您在.each 中定义breaker,那么每次调用.each 时它始终是一个新对象。我们不希望这样——我们希望breaker 在所有_ 中都相同
    • @pure_code 不要关注它是{} 的事实。这只是_ 本身用作“内部标志”的东西,表示应该打破.each 循环。
    • @pure_code 在技术上是可以的,但问题是理论上你可以在循环中与字符串 'break' 进行比较,这将是一个问题。 breaker = {} 只能有一个实例
    • @pure_code 不,不一样;如果您知道哈希摘要是什么,您可以仍然将它作为数组的一个元素,这会导致意外的循环中断。只能有一个 breaker
    • @pure_code 不是我所知道的没有某种调试工具
    【解决方案4】:

    + 前缀将值转换为数字。

    【讨论】:

      【解决方案5】:

      如果对象没有length 属性(作为常规Object,而不是Array),则调用obj.length 将返回undefined。对 undefined 的测试会更清晰,但实现者选择先将其转换为数字(因此它将变为 NaN),然后将其与原始值进行比较(使用严格比较,这将确保它将产生 @987654327 @)。

      更新:正如其他人指出的那样,这段代码似乎不仅与Arrays 有关,而且还与“类似数组”的对象(即具有数字length 属性的对象有关和数字索引)。在这种情况下,仅测试 instanceof Array 是不够的(并且仅测试 undefined 可能不是最佳选择,因为可能存在 length 但属于另一种类型)。

      【讨论】:

      • 这不是这个比较的目的
      • @Dancrumb 那么它有什么用呢?我看到两个代码块,一个处理数组(使用for),另一个处理对象(使用“foreach”)。我的解释错了吗?
      • undefined 的数字转换变为NaN,而不是0
      • 一方面,对象可以合法地拥有length 属性。因此,检查 undefined 是不够的
      • @Dancrumb 通过确保未强制转换的“length”属性等于转换为数字的“length”属性,代码实际上与“length”属性的测试相同以及该属性是否为数字的联合测试。因此,这是一个“鸭子打字”测试,看看对象是否是一个数组。
      猜你喜欢
      • 2016-05-12
      • 2023-03-25
      • 2021-10-22
      • 2015-01-30
      • 2013-04-23
      • 1970-01-01
      • 2017-11-26
      • 2010-12-29
      • 1970-01-01
      相关资源
      最近更新 更多