【问题标题】:Why is there a `null` value in JavaScript?为什么 JavaScript 中有一个“null”值?
【发布时间】:2009-01-20 16:12:46
【问题描述】:

在 JavaScript 中,有两个值基本上表示“我不存在” - undefinednull

程序员没有分配任何东西的属性将是undefined,但为了使属性成为null,必须显式分配null

我曾经认为null 是有必要的,因为undefined 是一个原始值,而null 是一个对象。不是,即使 typeof null 会产生 'object':实际上,两者都是原始值 - 这意味着 undefinednull 都不能从构造函数返回,因为两者都将转换为空对象(一个必须抛出错误才能在构造函数中声明失败)。

它们在布尔上下文中也都评估为false。我能想到的唯一真正区别是,在数字上下文中,一个计算为 NaN,另一个计算为 0

那么为什么同时存在undefinednull 如果这只会让程序员在试图找出是否已设置属性时错误地检查null 感到困惑?

我想知道的是,是否有人有一个合理的例子,说明有必要使用 null 而不能使用 undefined 来表达。

所以普遍的共识似乎是undefined 表示“没有这样的财产”,而null 表示“财产确实存在,但没有价值”。

如果 JavaScript 实现实际上会强制执行此行为,我可以接受 - 但 undefined 是一个完全有效的原始值,因此可以轻松地将其分配给现有属性以破坏此契约。因此,如果要确定某个属性是否存在,则无论如何都必须使用in 运算符或hasOwnProperty()。再说一遍:undefinednull 的单独值有什么实际用途?

当我想取消设置不再使用但不想delete 的属性值时,我实际上使用了undefined。我应该改用null 吗?

【问题讨论】:

  • 回答你的最后一个问题:不,你不应该将属性设置为undefined
  • "undefined" 只是全局范围内的一个变量,其原始值是“undefined”。可以为变量定义另一个值:{ undefined="Hello"; alert(undefined);} 一种更可靠的未定义测试方法:{ if (typeof myvar === "undefined") alert("undefined")}
  • 请参阅ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf 中的第 4.3.9 - 12 节了解 undefined/null,了解 15.1.1.3 了解全局范围内的变量“undefined”。
  • 您应该删除一个对象或将其设置为 null 如果这更有意义,但不要设置为 undefined。
  • In JavaScript, there are two values which basically say 'I don't exist' - undefined and null. 不,只有undefined 这么说。

标签: javascript null language-features undefined


【解决方案1】:

问题并不是“为什么 JS 中有一个空值”——在大多数语言中都有某种空值,它通常被认为非常有用。

问题是,“为什么 JS 中有一个 undefined 值”。主要使用场所:

  1. 当您声明 var x; 但未分配给它时,x 保持未定义;
  2. 当您的函数获得的参数少于其声明时;
  3. 当您访问不存在的对象属性时。

null 对于 (1) 和 (2)* 肯定同样有效。 (3) 真的应该立即抛出异常,而不是返回这个稍后会失败的怪异undefined,而是它不会直接抛出异常的事实,这是调试困难的一大来源。

*:您也可以争辩说 (2) 应该抛出异常,但是您必须为默认/变量参数提供更好、更明确的机制。

然而,JavaScript 最初并没有例外,也没有任何方法可以询问对象是否有某个名称下的成员 - 唯一的方法是(有时仍然是)访问该成员并查看您得到了什么。鉴于null 已经有一个目的,并且您可能希望为其设置一个成员,因此需要一个不同的带外值。所以我们有undefined,正如你所指出的那样,它是有问题的,它是我们永远无法摆脱的另一个很棒的 JavaScript“功能”。

当我想取消设置不再使用但不想删除的属性的值时,我实际上使用了 undefined。我应该改用 null 吗?

是的。将undefined 保留为特殊值,用于在其他语言可能引发异常时发出信号。

null 通常更好,但在某些 IE DOM 接口上,将某些内容设置为null 可能会给您一个错误。通常在这种情况下,设置为空字符串往往会起作用。

【讨论】:

  • 参数是可扩展的。您可以随心所欲地加入,一个函数可能会迭代并利用它们。可以随时为对象分配新属性。这些都是强大的功能,但我怀疑按照您的意愿抛出异常会产生很多开销。 IMO,值得权衡。我在 JS 中检查存在性所花费的时间比我通常在更严格的语言范式中进行的转换花费的时间要少得多。
  • 有趣的是,一个问题的公认答案是如何以“这不是真正的问题......”开始的。
  • @bobince 早期版本的 JS 没有 in 运算符或 hasOwnProperty 吗?因为在检查对象上是否存在属性方面,它们比 obj.hello !== undefined 安全得多。
  • 没关系,我回答了我自己的问题。根据 MDN,它们都是在 ES3 中引入的。
  • 添加到“使用 [undefined] 的主要场所”列表中:(4) 当函数完成执行但未显式返回值时。
【解决方案2】:

最好的描述here,但总结一下:

undefined 是缺少类型和值,null 是缺少值。

此外,如果您进行简单的“==”比较,那么您是对的,它们的结果是一样的。但试试 ===,它同时比较类型和值,你会发现区别。

【讨论】:

  • 我知道null !== undefined - 我的问题是为什么需要两个表达相同语义概念的东西?此外,您的链接提到“null 是一个对象” - 这是错误的,它是一个原始...
  • 它们不是同一个语义概念。至少对我而言,分配空值的属性与不存在的属性之间存在显着差异。
  • 但仅此而已,它们不是同一个语义概念。为了方便程序员,使用 == 时会强制 Null 表示相同的内容。
  • @EricElliott: typeof 谎言 - 阅读规范或尝试从构造函数返回 null
  • @EricElliott:构造函数的返回值与falsy-ness无关,但与object-ness有关:如果返回值是一个对象,则返回它;如果是null42 之类的原语,则丢弃返回值并返回新创建的对象
【解决方案3】:

我认为没有任何理由同时拥有nullundefined,因为许多人建议的唯一原因(“undefined 意味着没有这样的变量/属性”)是无效的,至少在 JavaScript 中。 undefined 无法告诉你变量/属性是否存在。

console.log(foo);               // "ReferenceError: foo is not defined"
                                // foo does not exist
var foo;
console.log(foo);               // "undefined", a different response
console.log(foo === undefined); // "true", but it does exist

var obj = {};
console.log(obj.hasOwnProperty("foo")); // "false", no such property
obj.foo = undefined;
console.log(obj.hasOwnProperty("foo")); // "true", it exists and has the value "undefined"
console.log(obj.foo === undefined);     // "true", but it does exist

obj.bar = "delete me";
obj.bar = undefined;
console.log(obj.hasOwnProperty("bar")); // "true", not actually deleted
delete obj.bar;
console.log(obj.hasOwnProperty("bar")); // "false", deleted

如您所见,检查foo === undefined 并不能告诉您foo 是否存在,设置obj.bar = undefined 并不会真正删除bar

undefined 应该代表“不存在”可能是 JavaScript 作者的初衷。但是,实现的结果并非如此。

【讨论】:

  • 将上面的代码示例中的undefined 替换为null,响应都是一样的。我不确定这如何回答这个问题。这是在评论别人的回答吗?
  • @EricElliott 我对这个问题的回答是,没有理由同时拥有nullundefined,因为许多人建议的唯一原因是无效的。
  • 您应该编辑您的答案并实际说出来。如果你给出了这个答案,我可能会投票。 =)
  • @EricElliott 我认为你是对的。我已经编辑了我的答案。谢谢!
  • 这个例子实际上表明如果你没有分配一个变量,它会返回undefined。但是,如果您确实将 undefined 分配给它,它实际上不是 undefined - 它是用 undefined 定义的并且引用了它。 undefinednull 之间的唯一区别是它们的用途和历史用途。它们都是原子的。
【解决方案4】:

两者都需要是完全可能的。例如,如果您查询 WMI,则完全有可能让一个类返回具有空值的属性。它们是被定义的,它们恰好在当时保持为空。

【讨论】:

    【解决方案5】:

    我认为您关于 JavaScript 将 undefined 定义为“没有这样的属性”和 null 定义为“该属性没有价值”的结论是完全正确的。在像 JavaScript 这样动态的语言中,这是一个非常重要的区别。使用鸭子类型意味着我们需要能够区分不存在的属性和不具有值的属性。它是我们获取类型信息的主要方式。在静态类型语言中,字段为空和字段不存在之间有明确的区别。在 JavaScript 中,这没有什么不同。但是,它会在运行时进行检查,并且可以在此之前进行修改。

    我将不得不同意这种实现很奇怪,因为很多时候这种区别是模糊的。但是我认为在 JavaScript 中区别很重要。并且能够分配undefined 是必不可少的。

    我记得不久前读过一篇关于用 JavaScript 编写的在线 RPG 的博客文章。它使用了一些示例,其中对象被创建为现有实例的副本而不是原型(类、函数等),然后被更改。这真的让我明白了undefined 在修改现有对象时的强大功能,但我不记得是谁写的了。

    【讨论】:

    • 能分享一下这个RPG吗?
    【解决方案6】:

    在语义上它们意味着不同的东西。 null 类型在其域中只有一个值,null 并且可以为属性分配此特定值。未定义表示明显缺少任何已分配的值。

    【讨论】:

    • 但是您可以使用undefined 很好地分配给属性,所以这个合同(如果没有这样的属性,只返回undfined)很容易被程序员破坏......
    • 可以,但绝对不应该。 Undefined 在 JavaScript 中用作非常基本/简单的异常形式 - 不要将其用作值并将其分配给某些属性!真是个疯子。
    【解决方案7】:

    作为一名 Java 程序员,我发现 undefined 和 null 之间存在巨大差异。编写 JavaScript 代码不多,因为 JavaScript 不是强类型的,并且 undefined 和 null 之间的区别被运行时经常执行的自动转换模糊了。顺便说一句,我经常利用这些转换;它们使我的 JS 代码更加紧凑和可读。

    为了回答您的问题,未定义意味着从未设置过值。实际上,这通常指向一个错误。如果 yourObject.property 未定义,则意味着您由于某种原因没有设置该属性,或者我正在寻找根本不存在的东西。在与多个编码员一起处理项目时,这是一个真正的问题。

    null 表示明确设置了“无值”。实际上,您是在告诉我有关该属性的一些信息,可能是在此上下文中未使用它,或者尚未确定值。

    在 Java 中,尝试访问未定义的字段总是会导致异常。事实上,编译器可以在你的代码中警告你。

    【讨论】:

      【解决方案8】:

      试试这个例子:

      <html>
      <head>
          <script type="text/javascript">
              function ShowObjProperties(obj) {
                  var property, propCollection = "";
      
                  for(property in obj) {
                      propCollection += (property + ": " + obj[property] + "\n");
                  }
      
                  alert(propCollection);
              }
      
              var obj = {
                  userid: 3,
                  name: 'me!',
                  speak: function() { alert('Hi! My name is ' + this.name + ' and my ID is ' + this.userid + '.'); }
              }
      
              //Shows all properties
              ShowObjProperties(obj);
      
              //The Speak function is no longer in the list!
              delete obj.speak;
              alert(typeof obj.speak);
              ShowObjProperties(obj);
      
              //The UserID is still listed, it just has no value!
              obj.userid = null;
              ShowObjProperties(obj);
          </script>
      </head>
      <body>
      
      </body>
      </html>
      

      我认为这里有两种不同类型的非常实际的用途。

      【讨论】:

      • 在我认为的原型中,成员是 null 还是未定义。
      • 但这只有在没有人试图破坏它时才有效 - 如果我设置 obj.userid = undefined,它将失败 - 请参阅我的问题的最后编辑
      【解决方案9】:

      归结为 javascripts 的动态特性。

      事物可能是未定义的,以便以后可以添加。这可以说是 javascript 如此强大和可扩展的原因。

      【讨论】:

      • 这与我的问题有什么关系?
      • 它是相关的,因为它回答了你的问题。 “null”是一种“单例”,表示“没有价值”。 'undefined' 是在告诉你某事是……令人震惊的,我知道……没有定义。它们是完全不同的东西。
      【解决方案10】:

      如果您将程序包装在 javascript 的事件范式中,这是一个重要的语言特性。

      // a key exists as a placeholder for something
      if(obj[name] === null) 
      // no key exists int eh hashtable that is in this object
      if(obj[name] === undefined)
      

      如果您正在处理一组数据,该数据集需要一个值来表示“无”来指示某些操作,而不是使用“无”来指示默认操作。

      filter_func_pt = {
        date:function(d){ return Math.round(d.getTime()/1000);},
        user: null,
      }
      
      function transform(obj){
          var ret = {};
          for( var prop in obj){
             var f = filter_func_pt[prop];
             if(f)
                ret[prop] = f(obj);
             else if(filter_func_pt[prop] === null)
               continue;
             else
               ret[prop] == obj;
          }
        return ret;
      }
      
      var a = {
         date: new Date(),
         user: 'sam'
         votes: [23, 41, 55] 
      };
      
      var b = transform(a);
      
      /* b = {
       *    date: 1298582417
       *    votes: [23, 41, 55]
       * }
       */
      

      在上面的代码中,null 关键字和undefined 服务器很清楚,用途不同。在返回 undefined 的 filter_func_pt 对象中找不到的查找意味着将属性按原样添加到返回对象中,而 null 值表示应该保留该值, 并且没有被添加,并且在这种情况下,任何真值的存在都表示一个函数,用于在将值添加到 ret 对象之前转换该值。

      【讨论】:

      • 这个例子是人为的,有点荒谬。 Null 根本没有阐明您的意图——相反,它掩盖了它。您可以使用更明确的字符串来阐明含义。例如,“保留”或“剥离”,然后您还可以更明确地了解函数类型并实际检查函数的存在。
      【解决方案11】:

      null 很漂亮

      与所有其他类型的实时脚本一样。

      cite:在 JavaScript 中,有两个值基本上表示“我不知道” 存在' - 未定义且为空。

      你为什么要说不正确的话?!

      "null""empty Object",就像 "0" 是 "empty Number"。 0,什么都不是——但它作为数字类型存在。 null 当然也是空的,但“它是”,它是一个定义明确的Object Type

      通常将这些东西称为“类型”,而实际上它们不是。事实上,它们是“类别”。但现在已经结束了。

      所以会坚持说“null”是一种没有种类的对象类型。 而“null”表示“我非常存在[!],但我没有我喜欢的内容”。

      undefined 缺少类型和种类,而 undefined 恰好也是它的类型定义。类型的未定义类型成为其独特的类型。 一种[“无”存在吗?你如何定义“无”?]问题。

      cite: 构造函数不能返回 undefined 或 null, 因为两者都将转换为空对象

      你又一次说了不正确的话。当然不是,“未定义”不是 Object,它是我们人类理解的普通 Token;但与 null 相反的是 - 它告诉你:它的类型是正确的,但你正在寻找的 Kind 不包含在其中,或者至少 - 目前不包含。稍后我们将\assign 一些对象放入其中时来拜访我们。

      cite:我能想到的唯一真正的区别是一个评估为 NaN,其他在数字上下文中为 0。

      这说明了它们的核心区别的全部意义,如前所述:undefined 是一个简单的标记,因为它由与其远亲相同的“遗传”材料组成:字符串,[ +undefined ] 操作会将其转换为 NaN,类似地,null 当然会将自身变形为正确的类型 0 \Number,而不是 undefined 将变形为字符串(!不是空的!),这正是它产生 NaN 的原因。其中:+undefined >> +"undefined" >> NaN。由于数字上下文需要明确的值。

      虽然布尔上下文需要引用 - 找不到要转换的内容并产生“假”。

      让我们现在切入...

      引用:所以再一次:单独值的实际用途是什么? 未定义且为空?

      我会尽量只给你两个经验性的例子,希望足够

      oElement.onclick >> null
      

      //表示-属性存在;其预期值为Type:Object,并且oElement支持“onclick”事件!

      oElement.innerText >> ""
      

      //表示-属性存在;其预期值为Type:String,表示oElement支持“innerText”属性。

      在这两种情况下 - 如果您收到“未定义”,则表示该属性不存在;不受支持或有错误的(ua 供应商)实现。

      保持霜冻,玩得开心。

      【讨论】:

      • 不要破坏你的帖子,埃涅阿斯。如果您想删除您的贡献,请删除它们(使用此评论上方的 删除 按钮)。
      • 没有删除按钮 - 但如果你看到它 - 请点击它!
      【解决方案12】:

      在阅读了关于 undefined vs null 的精彩讨论后,在 google 上的少量搜索将我带到了 Mozilla 文档 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null 有人提到—— null 通常在可以预期对象但没有对象相关的地方检索。

      Isn't 类似于 Null 对象模式 https://en.wikipedia.org/wiki/Null_object_pattern

      所以我想拥有 Null 数据类型是有意义的。

      文档也被称为 typeof null // “object”(不是“null”,因为遗留原因)

      不确定遗留原因是什么

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-22
        • 2021-01-31
        • 2020-07-25
        • 2014-10-21
        • 1970-01-01
        相关资源
        最近更新 更多