为什么JavaScript中会有一个“空”值?


115

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

程序员未分配任何东西undefined的属性将是,但是为了使该属性成为nullnull必须明确为其分配一个属性。

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

它们都false在布尔上下文中求和。我能想到的唯一真正的区别是,一个在数字上下文中求值NaN,另一个0在求值。

那么为什么同时存在这两个问题,undefinednull是否使null试图找出属性是否已设置的错误检查程序员感到困惑呢?

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

因此,普遍的共识似乎是undefined指“没有这种财产”,而null意味着“该财产确实存在,但没有价值”。

如果JavaScript实现实际上可以执行此行为,那么我可以接受-但是它undefined是一个完全有效的原始值,因此可以轻松地将其分配给现有属性以破坏此合同。因此,如果要确定属性是否存在,则必须使用in运算符或hasOwnProperty()仍然使用。所以再次:什么是用于分隔值的实际使用undefinednull

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


3
要回答最后一个问题:不,您不应将属性设置为undefined
Shog9年9

4
“未定义”只是全局范围内具有原始值“未定义”的变量。可以为变量定义另一个值:{undefined =“ Hello”; 警报(不确定);}一个更可靠的方式来测试未定义:{如果(typeof运算MYVAR ===“未定义”)警报(“未定义”)}
一些

1
有关undefined / null的信息,请参见ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf中的4.3.9-12;有关全局范围内的变量“ undefined”,请参见15.1.1.3
一些

1
您应该删除对象或将其设置为null(如果更有意义),但不要将其设置为undefined。
一些

4
In JavaScript, there are two values which basically say 'I don't exist' - undefined and null.不,只能undefined这么说。
Lightness Races in Orbit

Answers:


78

问题并不是真正的“为什么JS中没有null值”-大多数语言中都存在某种null值,通常认为它非常有用。

问题是“为什么JS中没有未定义的值”。使用它的主要地方:

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

null当然对于(1)和(2)*也同样适用。(3)实际上应该立即抛出异常,并且它不会返回异常,而不是返回undefined稍后将失败的怪异事实,这是调试困难的一大根源。

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

但是JavaScript最初没有例外,也没有任何方法询问对象是否具有某个特定名称的成员-唯一的方法是(有时仍然是)访问该成员并查看获得的内容。鉴于null已经有一个目的,并且您可能想要为其设置成员,则需要一个不同的带外值。因此undefined,正如您所指出的,这是有问题的,这是我们永远无法摆脱的另一个很棒的JavaScript“功能”。

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

是。保持undefined当其他语言可能会引发异常时,信号的特殊值。

null通常是更好的选择,但在某些IE DOM接口上,将设置为null可能会给您带来错误。在这种情况下,通常将空字符串设置为有效。


10
Args是可扩展的。您可以随意插入任意数量,函数可能会迭代并充分利用它们。可以随时为对象分配新属性。这些都是强大的功能,但是我怀疑抛出异常(如您所愿)会产生大量开销。IMO,这是值得权衡的。与用严格的语言范例进行转换相比,我花费更少的时间检查JS中的存在性。
埃里克·雷彭

有趣的是,问题的答案如何开始于“这不是问题……”
菲利普(Phillip)

@bobince早期的JS版本没有in运算符hasOwnProperty吗?因为它们比obj.hello !== undefined检查对象上是否存在属性安全得多。
安迪

没关系,我回答了我自己的问题。根据MDN的介绍,它们都是在ES3中引入的。
安迪

37

最好在这里描述,但总结如下:

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

此外,如果您进行简单的“ ==”比较,那么您是对的,它们的结果相同。但是尝试===,它同时比较类型和值,您会注意到其中的区别。


1
我知道null !== undefined-我的问题是,为什么需要表达相同语义概念的两件事?同样,您的链接中提到“空是对象”-是的,这是原始的……
Christoph

2
它们不是相同的语义概念。至少对我而言,为属性分配空值和不存在属性之间存在显着差异。
丹尼尔·谢弗

就是这样,它们不是相同的语义概念。为了方便程序员,在使用==时,将Null强制表示相同的内容。
埃迪·帕克

1
@EricElliott:typeof谎言-阅读规范或尝试null从构造函数中返回
Christoph

5
@EricElliott:构造函数的返回值与虚假性无关,而与object-ness无关:如果返回值是一个对象,则返回该对象;如果它是类似nullor 的原始类型42,则放弃返回值并返回新创建的对象
Christoph

17

我认为没有理由同时使用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

JavaScript作者的原始意图undefined可能代表“不存在”。但是,实现方式并非如此。


1
在上面的代码示例中替换undefinednull,并且响应都相同。我不确定这如何回答问题。这是对别人的回答发表评论吗?
Eric Elliott

1
@EricElliott我对这个问题的回答是,没有理由同时使用nullundefined,因为许多人提出的唯一理由是无效的。
赵雷

您应该编辑答案,然后说出来。如果您给出了答案,我可能会赞成。=)
埃里克·埃利奥特

@EricElliott我认为你是对的。我已经编辑了答案。谢谢!
雷朝

3
该示例实际上表明,如果您未分配变量,则返回undefined。但是,如果您确实分配undefined了它,则它实际上不是undefined-它是使用它定义的,undefined并且已经对其进行了引用。undefined和之间的唯一区别null是它们的用法和历史目的。它们都是原子的。
Aleksej Komarov 2014年

6

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


6

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

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

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


您能分享这个角色扮演游戏吗?
迈克尔

3

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


1
但是您可以undefined很好地使用它来分配属性,因此undfined程序员可以轻松地破坏此合同(只有在没有此类属性时才返回)...
Christoph

2
可以,但是您绝对不能。Undefined在JavaScript中用作一种非常基本/简单的异常形式-请勿将其用作值并将其分配给某些属性!那个疯子。
rfunduk

3

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

要回答您的问题,未定义表示从未设置值。实际上,这通常表示一个错误。如果yourObject.property未定义,则意味着您由于某种原因未设置该属性,或者我正在寻找根本不存在的属性。当一个项目使用多个编码器时,这是一个实际的问题。

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

在Java中,尝试访问未定义的字段将始终导致异常。实际上,可以使编译器在您的代码中警告您。


0

试试这个例子:

<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或只是未定义。
Kev

但这仅在没有人试图打破它的情况下才有效-如果我设置了obj.userid = undefined它,它将失败-请参阅我的问题的最后编辑
Christoph

0

归结为javascript的动态性质。

事物可能是不确定的,因此可以在以后添加它们。这可以说是为什么javascript如此强大且可扩展的原因。


这与我的问题有什么关系?
Christoph

2
这很重要,因为它回答了您的问题。“ null”是一种“单一”,表示“没有价值”。“未定义”告诉您某事令人震惊,我知道……未定义。他们是完全不同的东西。
rfunduk

0

如果您将程序包装在事件的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)

如果您要处理的数据集需要一个值来表示“ nothing”来表示某些操作,而不是使用“ nothing”来表示默认操作,则这非常有用。

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关键字和未定义的服务器非常清楚且用途不同。在未定义的filter_func_pt对象中找不到查找(返回未定义)意味着将属性按原样添加到返回对象中,而null值指示应保留该值,而不要添加该值,并且在此值中存在任何真实值case表示一个用于在将值添加到ret对象之前转换值的函数。


这个例子是人为的,有点荒谬。Null根本无法澄清您的意图,而是掩盖了它。您可以在其中使用更明确的字符串来阐明其含义。像“预扣”或“小条”,然后您还可以更加明确地了解函数类型,并实际检查函数是否存在。
埃里克·埃利奥特

0

null是美丽的

以及所有其他类型的实时脚本。

引用:在JavaScript中,有两个基本上表示“我不存在”的值-未定义和null。

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

就像“ 0”是“空数”一样,“ null”“空对象。0,什么都不是-但它作为数字类型存在。 null当然也为空,但是“它是”,这是Object Type的明确定义。

当它们不是“类型”时,通常将它们称为“类型”。实际上,它们是“类别”。但这已经结束了。

因此,坚持说“ null”是没有种类的对象类型。“ null”表示“我非常存在[!],但是我没有类似的内容”。

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

引用:构造函数可以返回undefined或null,因为两者都将转换为空对象

您设法再次说错了话。当然不是,“未定义”不是对象,它是我们人类理解的普通令牌;但与此相反,null是-并告诉您:它的Type是正确的,但是您要查找的Kind不在其中,或者至少-目前没有。以后,当我们在其中放置\分配一些对象时,请访问我们。

引用:我能想到的唯一真正的区别是,在数值上下文中,一个评估为NaN,另一个评估为0。

如上所述,这就是它们核心区别的全部要点:undefined是一个简单的令牌,由于它是由与它的远亲相同的“遗传”材料组成的:字符串,因此[+ undefined]操作会将其转换为NaN,类似的null当然会自动将自己变形为正确的类型0 \ Number,与undefined相反,它将转换为字符串(!这不是空的!),这就是为什么它会产生NaN的原因。其中:+ undefined >> +“ undefined” >> NaN。由于数字上下文期望显式值。

布尔值上下文需要引用时-找不到任何要转换的内容并产生'false'。

现在让我们开始吧...

引用:所以再一次:undefined和null的单独值的实际用途是什么?

我将尝试仅给您两个经验例子,并希望足够

oElement.onclick >> null

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

oElement.innerText >> ""

//意味着-该属性存在;它的期望值是Type:String,这意味着oElement支持“ innerText”属性。

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

保持霜冻,玩得开心。


埃涅阿斯,不要破坏您的帖子。如果您想删除贡献,请删除它们(使用此评论上方的“ 删除”按钮)。
迈克尔·彼得罗塔

没有删除按钮-但如果您看到它-请单击它!

0

在阅读了有关未定义vs空的惊人讨论之后,在Google上进行的很少搜索就把我带到了Mozilla文档 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null 提到-空通常是在可以预期对象但没有对象相关的地方检索。

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

因此,我认为具有Null数据类型是有意义的。

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

不知道是什么遗留原因

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.