【问题标题】:Falsey values in JavaScriptJavaScript 中的虚假值
【发布时间】:2010-10-20 21:55:05
【问题描述】:

我今天有一个有趣的面试问题,让我有点难过。我被问及虚假的价值观。所以 undefined、NaN、null、0 和空字符串都评估为 false。这在 JavaScript 中很有用的原因是什么?我唯一能想到的就是不必这样做:

if (mystring === '' || mystring === undefined) { }

我可以这样做:

if (!mystring)

这是唯一有用的应用程序吗?

【问题讨论】:

  • NaN 代替 NAn,null 代替 Null(JavaScript 区分大小写)
  • 您必须热爱编程的一件事是必须跟上(英语)语言术语。 “假”真的是一个合法的编程术语,还是仅仅意味着“假值”?如果它是-real- 术语,而不仅仅是极客说话,那么定义它的 url 在哪里,因为我似乎无法找到该术语的合法定义。
  • @Bill 我猜“truthy”和“falsy”是新词然后...javascript.crockford.com/style2.html
  • @bill...老实说,昨天是我第一次听到它。我接受采访的人提到了它。我们还谈到了道格拉斯·克罗克福德,所以他可能从那里得到了条款。
  • 相关:真实字符串值stackoverflow.com/a/5515349/759452

标签: javascript


【解决方案1】:

在检查某个属性是否存在时,您必须注意一个危险的错误值问题。

假设您想测试一个新属性的可用性;当此属性可以实际上具有0"" 的值时,您不能简单地使用检查其可用性

if (!someObject.someProperty)
    /* incorrectly assume that someProperty is unavailable */

在这种情况下,您必须检查它是否真的存在:

if (typeof someObject.someProperty == "undefined")
    /* now it's really not available */

还要注意NaN 不等于任何东西,甚至不等于它自己 (NaN != NaN)。

【讨论】:

  • 但是您可以合法地将属性设置为未定义,从而打破了这个测试。使用 someObject.hasOwnProperty 几乎肯定会更好,如果您真的关心该属性是否存在于对象原型链中的任何位置,请递归检查。
  • @Angiosperm 在 JavaScript 中,对象无论如何都是动态的,所以没有属性的对象和属性设置为undefined的对象之间没有实际区别。
  • @Šime Vidas 场景:我们的应用程序调用某个远程位置来检查资源是否存在。在应用程序的生命周期中,资源的存在是不变的。这种检查可能很昂贵,所以我们要开始缓存调用的结果。让我们将对象的某些属性设置为该调用的结果。现有代码仅检查调用结果是否为“未定义”以确定资源是否存在。为了不必更改我们当前的接口,缓存机制必须检查适当的属性是否确实存在,而不仅仅是未定义。
  • 不需要检查typeof。如果你想检查一个属性是否存在,你通常会想知道它是未定义的还是空的。对于该检查,请执行 if (someObject.someProperty == null)。如果您只想检查它是否未定义,请执行 if (someObject.someProperty === undefined)。
  • @Adam:一个缺点:undefined可能被覆盖。或使用in 运算符:if ("property" in object)
【解决方案2】:

JavaScript 中的“假”值有两个不同的问题。

首先是官方的转换方案,也就是 Boolean(x) 返回的内容。当 x 为 false 或 0 或 NaN 或 null 或 undefined 或 "" 时返回 false,否则返回 true。这与

的行为相同
if (condition) {/*true path*/} else {/*false path*/}

也就是说,如果 Boolean(condition) 返回 false,则执行错误路径,否则执行真实路径。此行为通常用于检查是否定义了属性。但是,这样做是不安全的,除非您确定如果定义了该属性将是一个对象或数组。测试是否定义了属性的最安全方法是执行

if (property != null) { /*property is defined*/} 

确保属性不为空或未定义。如果您只想确保该属性不是未定义的,请执行

if (property !== undefined) { /*property is not undefined (but may be null)*/ } 

(注意 !== 中的额外 =)。

其次,所有 == false 的值。这是可以强制为 0 的所有内容(这是强制为 false 的内容)。这包括所有转换为 false 的值,除了 NaN(它不能 == false 因为它从不 == 任何东西)、null 和未定义。但它也包括在转换为字符串然后转换为数字时等于 0 的所有对象。例如,这包括在转换为字符串时为空字符串“”或“0”或“-0”的所有对象" 或 "+0" 或 "0x00" 或 "000" 或 "0e0" 或 "0.0000"....例如,

({toString: function() {return "-00.0e000";}}) == false

是真的。有趣的是,这包括空数组,以及任何只包含一个返回空或 0 字符串的其他项的数组嵌套,因为呈现为字符串的数组仅显示不带括号的内容。也就是说,

[[[[0]]]] == false; // Because [[[[0]]]].toString() === "0"
[] == false;
[[[""]]] == false;
["0"] == false;
[[({toString: function() {return "0";}})]] == false;

计算 == false 的完整算法描述为 here

这很重要的原因是,如果您不了解这些规则中的大部分内容,它可能会导致难以发现的细微错误。最重要的收获可能是 if (condition) 的工作原理以及使用 === 可以避免大多数其他疯狂的东西。

【讨论】:

    【解决方案3】:

    了解它在 JS 中的工作原理很重要,因此您不会感到惊讶。不一定只是什么是虚假的,而是什么是真实的以及它们如何相互比较。

    一个例子是 '0' 被认为等于 0 与 ==,但它不等于 '' - 尽管 0 是。 JavaScript 比较并不总是可传递的。

    这意味着仅仅因为(foo==bar && bar==fizz) 为真,(foo==fizz) 并不总是为真。继续上面的例子,'0'==0, and 0=='', but '0'!='' - 因为你在后一种情况下比较字符串,所以它们被比较为字符串而不是强制到数字。

    【讨论】:

      【解决方案4】:

      重要的是要知道0 评估为false 以防止执行以下操作:

      if(str.indexOf('foo'))
      

      【讨论】:

      • 这将如何运作?当什么都没有找到时它返回-1,这不是一个假值..
      • @FelixKling:但在这种情况下,知道 0 评估为 false 并不重要。当 -1 评估为 false 时,0 也评估为 false 但并不表示没有找到任何东西这一事实将是一个绊脚石。
      • @Nick:我认为了解两者很重要,-1 是真实的,0 是虚假的。那时我可能还没有考虑过-1 的情况。在 PHP 中它会更严重,因为如果没有找到字符串,等效函数会返回 false
      • @FelixKling 这是有道理的。顺便提一句。 if(str.indexOf('foo') + 1) 应该像 expexted(在 JS 中)一样工作,但可读性不强..
      【解决方案5】:

      检测浏览器是否具有特定的预定义对象很有用:

      if(!!navigator.geolocation){
        // executes if the browser has geolocation support
      }
      
      if(!!document.createElement('canvas').getContext){
        // executes if the browser supports <canvas>
      }
      

      解释:navigator.geolocation 是一个对象或未定义。如果是对象!navigator.geolocation 将返回false,如果未定义则返回true。因此,要检查浏览器是否启用了地理定位,您需要再次“翻转”布尔值,方法是添加另一个 !

      【讨论】:

      • 所以如果我做了 if(!navigator.geolocation){ } 并且它是未定义的,那么这将返回 false?
      • 我不明白...if (!!foo.bar)if (foo.bar) 有什么区别?
      • @elduderino 不,它会返回 true。这 ! operator首先将其操作数转换为布尔值,然后切换它...如果navigator.geolocation未定义,则将其转换为布尔值false,然后切换为true...
      • 在这种情况下,没有。 !! 运算符用于将类型转换为布尔值,因此如果要将值显式转换为布尔值,请使用 !!value
      • 使用 Boolean(value) 显式类型转换为布尔值可能更好。它的可读性明显更高,而且字符不多。
      【解决方案6】:

      它们对于设置默认值也很有用...

      function foo(bar){
          alert(bar || "default");
      }
      

      我知道很多人都在尝试这样做

      if (typeof(foo) === "undefined"){}
      

      绕过虚假,但这有其自身的问题,因为

      typeof(null) === "object"
      

      由于某种原因

      【讨论】:

      • 是的,我知道 null。奇怪的。很好的例子。谢谢
      • @elduderine 关于 null 的一个更糟糕的事情是 isNaN(null) === false。
      • 您的 (bar || "default") 示例可能是反模式。这是因为它将触发您的函数用户可能打算作为 bar 值的空字符串(我在库中多次遇到此错误)。即使上下文意味着您理解这一点,您的函数的用户也不会清楚这是没有评论的情况。对于可能是字符串 ("")、数字 (NaN) 或布尔值 (false) 的值,最好完全避免使用这种样式。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-16
      • 2022-06-28
      • 1970-01-01
      • 2015-02-15
      • 2019-05-23
      • 1970-01-01
      相关资源
      最近更新 更多