ChatGPT解决这个技术问题 Extra ChatGPT

检测未定义的对象属性

检查 JavaScript 中的对象属性是否未定义的最佳方法是什么?

在此线程中查找最近的答案。在“现代”javascript 中,考虑使用 in 运算符:'key' in obj ? 'obj has key property' : 'obj does not have key property' `
如果您有一个新的“正确”答案,我愿意选择一个新的“正确”答案,它涵盖了与当前方法一样完整的旧方法,并且还解决了更现代的选择。

M
MWO

检查属性值是否为特殊值 undefined 的常用方法是:

if(o.myProperty === undefined) {
  alert("myProperty value is the special value `undefined`");
}

要检查一个对象是否实际上没有这样的属性,因此当您尝试访问它时默认返回 undefined

if(!o.hasOwnProperty('myProperty')) {
  alert("myProperty does not exist");
}

要检查与标识符关联的值是否是特殊值 undefined(如果该标识符尚未声明):

if(typeof myVariable === 'undefined') {
  alert('myVariable is either the special value `undefined`, or it has not been declared');
}

注意:这最后一种方法是引用 未声明 标识符而没有早期错误的唯一方法,这与具有值 undefined 不同。

在 ECMAScript 5 之前的 JavaScript 版本中,全局对象上名为“undefined”的属性是可写的,因此如果不小心重新定义了一个简单的检查 foo === undefined,它可能会出现意外行为。在现代 JavaScript 中,该属性是只读的。

但是,在现代 JavaScript 中,“未定义”不是关键字,因此函数内部的变量可以命名为“未定义”并隐藏全局属性。

如果您担心这种(不太可能的)边缘情况,您可以使用 the void operator 来获取特殊的 undefined 值本身:

if(myVariable === void 0) {
  alert("myVariable is the special value `undefined`");
}

如果某物为空,则它被定义(为空),但您可以结合too检查。上面代码的烦人细节是你不能定义一个函数来检查它,你可以定义这个函数......但是尝试使用它。
@neu-rah 为什么你不能写一个函数?为什么这样的东西不起作用?它似乎对我有用。有没有我不考虑的情况? jsfiddle.net/djH9N/6
@Zack 您对 isNullorUndefined 的测试没有考虑您调用 isNullOrUndefined(f) 并且 f 未声明的情况(即没有“var f”声明的情况)。
废话,现在有数千票。这是最糟糕的方法。我希望路人看到这条评论并决定检查……咳咳……其他答案。
您现在可以使用 obj !== undefinedundefined 过去是可变的,例如 undefined = 1234 会导致有趣的结果。但是在 Ecmascript 5 之后,它不再可写了,所以我们可以使用更简单的版本。 codereadability.com/how-to-check-for-undefined-in-javascript
D
Dave Jarvis

我相信这个话题有很多不正确的答案。与普遍看法相反,“未定义”不是 JavaScript 中的关键字,实际上可以为其分配一个值。

正确的代码

执行此测试的最可靠方法是:

if (typeof myVar === "undefined")

这将始终返回正确的结果,甚至可以处理未声明 myVar 的情况。

退化代码。不使用。

var undefined = false;  // Shockingly, this is completely legal!
if (myVar === undefined) {
    alert("You have been misled. Run away!");
}

此外,myVar === undefined 将在 myVar 未声明的情况下引发错误。


除了 Marks 评论,我没有得到这个:“myVar === undefined 将在 myVar 未声明的情况下引发错误。” - 为什么这很糟糕?如果我引用未声明的变量,为什么我不想出现错误?
另请记住,您始终可以执行 void 0 来获取 undefined 指向的值。所以你可以做if (myVar === void 0)0 并不特殊,您可以在其中放置任何表达式。
在现代浏览器(FF4+、IE9+、Chrome 未知)中,无法再修改 undefinedMDN: undefined
这个答案也是不正确的。问题是关于未定义的对象属性,而不是未定义的变量。有显着差异。例如,做 if (obj.field === undefined) 是完全合理的。我认为有人做var undefined = false;的风险被高估了。如果您想防止因糟糕的编程而导致的所有此类副作用,您将不得不进行不合理的防御性编程。
有趣的是,人们建议使用这些愚蠢且容易出错的 hack 来避免遮蔽 undefined(这只能由糟糕的开发人员完成),但他们却乐于使用其他可能也被遮蔽的全局标识符。奇怪。很奇怪。
R
Ry-

尽管这里的许多其他答案都强烈推荐,typeof 是一个糟糕的选择。它永远不应该用于检查变量是否具有值 undefined,因为它作为对值 undefined 和变量是否存在的组合检查。在绝大多数情况下,您知道变量何时存在,如果您在变量名或字符串文字 'undefined' 中输入错误,typeof 只会引入潜在的静默失败。

var snapshot = …;

if (typeof snaposhot === 'undefined') {
    //         ^
    // misspelled¹ – this will never run, but it won’t throw an error!
}
var foo = …;

if (typeof foo === 'undefned') {
    //                   ^
    // misspelled – this will never run, but it won’t throw an error!
}

因此,除非您正在执行特征检测²,不确定给定名称是否在范围内(例如检查 typeof module !== 'undefined' 作为特定于 CommonJS 环境的代码中的一个步骤),否则在变量上使用 typeof 是一个有害的选择,而正确的选择是直接比较值:

var foo = …;

if (foo === undefined) {
    ⋮
}

对此的一些常见误解包括:

读取“未初始化”变量(var foo)或参数(函数 bar(foo) { ... },称为 bar())将失败。这根本不是真的——没有显式初始化的变量和没有给定值的参数总是变得未定义,并且总是在范围内。

那个未定义的可以被覆盖。确实 undefined 不是关键字,但它是只读且不可配置的。尽管有非关键字状态(Object、Math、NaN……),但您可能无法避免使用其他内置函数,而且实用代码通常不是在积极的恶意环境中编写的,因此这不是一个很好的理由担心未定义。 (但如果您正在编写代码生成器,请随意使用 void 0。)

了解变量的工作方式之后,是时候解决实际问题了:对象属性。没有理由将 typeof 用于对象属性。前面关于特征检测的例外在这里不适用——typeof 仅对变量有特殊行为,引用对象属性的表达式不是变量。

这个:

if (typeof foo.bar === 'undefined') {
    ⋮
}

总是完全等价于 this³:

if (foo.bar === undefined) {
    ⋮
}

并考虑到上面的建议,以避免让读者对您使用 typeof 的原因感到困惑,因为使用 === 来检查相等性是最有意义的,因为以后可以将其重构为检查变量的值,并且因为它看起来更好,您也应该始终在此处使用 === undefined³

当涉及到对象属性时,需要考虑的另一件事是您是否真的要检查 undefined。给定的属性名称可以在对象上不存在(读取时产生值 undefined),以值 undefined 出现在对象本身上,以值 undefined 出现在对象的原型上,或者出现在任何一个上具有非 undefined 值的那些。 'key' in obj 将告诉您键是否位于对象原型链上的任何位置,Object.prototype.hasOwnProperty.call(obj, 'key') 将告诉您它是否直接在对象上。不过,我不会在这个答案中详细介绍原型和使用对象作为字符串键映射,因为它主要是为了反驳其他答案中的所有坏建议,而不管原始问题的可能解释如何。阅读object prototypes on MDN了解更多信息!

¹ 示例变量名的不寻常选择?这是来自 Firefox 的 NoScript 扩展的真正死代码。
² 不要假设不知道范围内的内容通常是可以的。滥用动态范围导致的额外漏洞:Project Zero 1225
³ 再次假设 ES5+ 环境并且 undefined 引用全局对象的 undefined 属性。


@BenjaminGruenbaum 是的,但完全具有误导性。任何非默认上下文都可以定义自己的 undefined,隐藏默认上下文。对于大多数实际目的而言,这与覆盖它具有相同的效果。
@blgt那是偏执的,与任何实际操作无关。每个上下文都可以覆盖 console.log,重新定义 Array 原型方法,甚至覆盖 Function.prototype.call` 挂钩,并在每次调用 JavaScript 中的函数时进行更改。防止这种情况是非常偏执且相当愚蠢的。就像我(和 minitech)说的那样,您可以使用 void 0 与 undefined 进行比较,但又一次 - 这是愚蠢和矫枉过正的。
我希望我有不止一张赞成票。这是最正确的答案。我真的不想在代码中看到 typeof something === "undefined")
这确实应该是公认的答案。这是最彻底和最新的。
任何非默认上下文也可以覆盖,例如 MathObjectsetTimeout,或者您希望在默认情况下在全局范围内找到的任何内容。
P
Peter Mortensen

在 JavaScript 中有 null 和 undefined。它们有不同的含义。

undefined 表示变量值没有被定义;不知道价值是什么。

null 表示已定义变量值并将其设置为 null(没有值)。

Marijn Haverbeke 在他的免费在线书籍“Eloquent JavaScript”(强调我的)中指出:

还有一个类似的值,null,意思是‘这个值被定义了,但是它没有值’。 undefined 和 null 之间的含义差异主要是学术性的,通常不是很有趣。在实际程序中,经常需要检查某个东西是否“有价值”。在这些情况下,可以使用表达式 something == undefined,因为即使它们的值不完全相同, null == undefined 也会产生 true。

所以,我想检查某些东西是否未定义的最佳方法是:

if (something == undefined)

对象属性应该以相同的方式工作。

var person = {
    name: "John",
    age: 28,
    sex: "male"
};

alert(person.name); // "John"
alert(person.fakeVariable); // undefined

if (something == undefined) 最好写成 if (something === undefined)
应该指出的是,这并不完全安全。 undefined 只是一个可以由用户重新分配的变量:编写 undefined = 'a'; 将导致您的代码不再执行您认为的操作。使用 typeof 更好,也适用于尚未声明的变量(不仅仅是属性)。
如果某物是未定义的全局变量,(某物 == 未定义)会引发 javascript 错误。
这样做的问题是,如果 var a = null 则 a == undefined 的计算结果为真,即使 a 是最肯定定义的。
这种对“Eloquent Javascript”注释的解释是落后的。如果您真的只想检查未定义,建议的代码将不起作用(它还将检测已定义但尚未关联任何值的条件 [ienull])。空值。建议的代码“if (something == undefined) ...”同时检查 undefined 和 null(未设置值),即它被解释为“if ((something is undefined) OR (something is null)) ...”作者所说的是,您真正想要的通常是检查未定义和空值。
K
Konstantin Smolyanin

这是什么意思:“未定义的对象属性”?

实际上它可能意味着两个完全不同的东西!首先,它可能表示从未在对象中定义的属性,其次,它可能表示具有未定义值的属性。让我们看一下这段代码:

var o = { a: undefined }

o.a 是否未定义?是的!它的值是未定义的。 o.b 是否未定义?当然!根本没有属性'b'!好的,现在看看在这两种情况下不同的方法是如何表现的:

typeof o.a == 'undefined' // true
typeof o.b == 'undefined' // true
o.a === undefined // true
o.b === undefined // true
'a' in o // true
'b' in o // false

我们可以清楚地看到 typeof obj.prop == 'undefined'obj.prop === undefined 是等价的,它们并没有区分那些不同的情况。而'prop' in obj可以检测到一个属性根本没有定义并且不关注可能未定义的属性值的情况。

那么该怎么办?

1)您想知道一个属性是否由第一个或第二个含义定义(最典型的情况)。

obj.prop === undefined // IMHO, see "final fight" below

2)您只想知道对象是否具有某些属性而不关心它的值。

'prop' in obj

笔记:

您不能同时检查对象及其属性。例如,this xa === undefined 或 this typeof xa == 'undefined' 引发 ReferenceError: x is not defined if x is not defined。

变量 undefined 是一个全局变量(实际上它在浏览器中是 window.undefined)。从 ECMAScript 第一版开始就支持它,从 ECMAScript 5 开始它是只读的。因此,在现代浏览器中,它不能被重新定义为真实的,因为许多作者喜欢用吓唬我们的方式来吓唬我们,但这对于旧浏览器来说仍然是真实的。

最后一战:obj.prop === undefined vs typeof obj.prop == 'undefined'

obj.prop === undefined 的优点:

它有点短,看起来有点漂亮

如果你拼错了 undefined,JavaScript 引擎会给你一个错误

obj.prop === undefined 的减号:

undefined 可以在旧浏览器中被覆盖

typeof obj.prop == 'undefined' 的优点:

真的是万能的!它适用于新旧浏览器。

typeof obj.prop == 'undefined' 的减号:

这里的 'undefned'(拼写错误)只是一个字符串常量,所以如果您像我刚才那样拼错了,JavaScript 引擎将无法帮助您。

更新(对于服务器端 JavaScript):

Node.js 支持将全局变量 undefined 作为 global.undefined(它也可以在没有“全局”前缀的情况下使用)。我不知道服务器端 JavaScript 的其他实现。


@Bergi 感谢您的评论。我已经更正了我的答案。在我的辩护中,我可以说目前(从 v.0.10.18 开始)official Node.js documentation 没有提及 undefined 作为 global 的成员。此外,console.log(global);for (var key in global) { ... } 都不会将 undefined 显示为 global 的成员。但是像 'undefined' in global 这样的测试显示相反。
it's in the EcmaScript spec 以来它不需要额外的文档,这也表明 [[Enumerable]] 是错误的 :-)
关于 Minuses of typeof obj.prop == 'undefined',这可以通过写成 typeof obj.prop == typeof undefined 来避免。这也提供了非常好的对称性。
@hlovdal:与 obj.prop === undefined 相比,这完全没有意义。
当我们对问题标题 Detecting an undefined property“ 真实时,对第一句中的(不同且更容易的)问题(“check if undefined. ..“),您回答 if ('foo' in o)...您的答案确实是这里的第一个正确答案。几乎所有其他人都只是回答这句话。
M
Michael Anderson

问题归结为三种情况:

该对象具有属性并且其值不是未定义的。该对象具有该属性,其值未定义。该对象不具有该属性。

这告诉我们一些我认为重要的事情:

未定义成员和具有未定义值的已定义成员之间存在差异。

但不幸的是,typeof obj.foo 并没有告诉我们我们有这三种情况中的哪一种。但是,我们可以将其与 "foo" in obj 结合起来以区分情况。

                               |  typeof obj.x === 'undefined' | !("x" in obj)
1.                     { x:1 } |  false                        | false
2.    { x : (function(){})() } |  true                         | false
3.                          {} |  true                         | true

值得注意的是,这些测试对于 null 条目也是相同的

                               |  typeof obj.x === 'undefined' | !("x" in obj)
                    { x:null } |  false                        | false

我认为在某些情况下,检查属性是否存在比检查它是否未定义更有意义(并且更清楚),并且这种检查不同的唯一情况是情况 2,这是罕见的情况对象中具有未定义值的实际条目。

例如:我刚刚重构了一堆代码,其中包含一堆检查对象是否具有给定属性的代码。

if( typeof blob.x != 'undefined' ) {  fn(blob.x); }

在没有检查未定义的情况下编写时更清楚。

if( "x" in blob ) { fn(blob.x); }

但正如已经提到的,这些并不完全相同(但对于我的需求来说已经足够好了)。


嗨迈克尔。很好的建议,我认为它确实让事情变得更清洁。然而,我发现的一个问题是使用 !带有“in”的运算符。你必须说 if (!("x" in blob)) {} 用括号括起来,因为!运算符优先于“in”。希望对某人有所帮助。
抱歉,迈克尔,但鉴于最初的问题,这是不正确的,或者至少是误导性的。 'in' 不足以测试对象属性是否具有未定义的类型。为了证明,请看这个小提琴:jsfiddle.net/CsLKJ/4
这两个代码部分做不同的事情! a = {b: undefined}给出的考虑和反对;然后是 typeof a.b === typeof a.c === 'undefined''b' in a!('c' in a)
+1。 OP 没有明确说明该属性是否存在并具有未定义的值,或者该属性本身是否未定义(即不存在)。
我建议将您的第一个表中的点 (2.) 更改为 { x : undefined },或者至少将其添加为表中 (2.) 的另一种选择 - 我不得不考虑片刻才能意识到点 (2.) 的计算结果到 undefined(尽管您稍后会提到)。
P
Peter Ajtai
if ( typeof( something ) == "undefined") 

这对我有用,而其他人没有。


括号是不必要的,因为 typeof 是一个运算符
但它们更清楚地说明了正在检查的内容。否则它可能会被读取为 typeof (something == "undefined")
如果你需要括号,那么你应该学习 JS 中的运算符优先级:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
括号之所以有用,正是因为你不需要学习 JS 中的运算符优先级,也不需要推测未来的维护程序员是否需要学习 JS 中的运算符优先级。
括号有助于澄清事情。但在这种情况下,它们只是让操作符看起来像一个函数。毫无疑问,这阐明了程序员的意图。但如果您不确定运算符优先级,您应该将其写为 (typeof something) === "undefined"
S
Simon East

我不确定将 ===typeof 一起使用的起源来自哪里,作为惯例,我看到它在许多库中使用,但是 typeof 运算符返回一个字符串文字,我们预先知道,所以为什么你也想输入检查吗?

typeof x;                      // some string literal "string", "object", "undefined"
if (typeof x === "string") {   // === is redundant because we already know typeof returns a string literal
if (typeof x == "string") {    // sufficient

伟大的埃里克。检查类型是否也会影响性能?
@Simon:恰恰相反-在“===”的情况下,避免强制执行可能会对性能造成轻微影响。快速而肮脏的测试表明 '===' 在 FF5.0.1 下比 '==' 快 5%
更彻底的测试表明,在 FF、IE 和 Chrome 下,'==' 或多或少比 '===' (5-10%) 快,而 Opera 根本没有任何区别:jsperf.com/triple-equals-vs-twice-equals/6
使用 == 仍然需要至少进行类型检查 - 解释器无法在不知道它们的类型之前比较两个操作数。
===== 少一个字符 :)
J
Joe Johnson

我没有看到(希望我没有错过)任何人在财产之前检查对象。所以,这是最短和最有效的(虽然不一定是最清楚的):

if (obj && obj.prop) {
  // Do something;
}

如果 obj 或 obj.prop 为 undefined、null 或“falsy”,则 if 语句将不会执行代码块。这通常是大多数代码块语句(在 JavaScript 中)中所需的行为。

更新:(2021 年 7 月 2 日)

最新版本的 JavaScript 为可选链引入了一个新运算符:?.

这可能是检查对象属性是否存在的最明确和最有效的方法,向前推进。

参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining


如果您想知道为什么会这样:Javascript: Logical Operators and truthy / falsy
如果您想将属性分配给已定义的变量,不为空也不为假,否则使用一些默认值,您可以使用:var x = obj && obj.prop || 'default';
我相信问题是针对未定义的明确检查。您的条件检查 JS 的所有错误值。
不要这样做,如果 obj.propfalse0"" 和其他各种错误值,它会失败。这正是我们不应该做的,也适用于不应该以这种方式使用的可选链接。
P
Peter Mortensen

从相关问题交叉发布my answerHow can I check for "undefined" in JavaScript?

具体到这个问题,请参阅 someObject.<whatever> 的测试用例。

说明各种答案结果的一些场景:http://jsfiddle.net/drzaus/UVjM4/

(请注意,在作用域包装器中使用 var 进行 in 测试会有所不同)

参考代码:

(function(undefined) {
    var definedButNotInitialized;
    definedAndInitialized = 3;
    someObject = {
        firstProp: "1"
        , secondProp: false
        // , undefinedProp not defined
    }
    // var notDefined;

    var tests = [
        'definedButNotInitialized in window',
        'definedAndInitialized in window',
        'someObject.firstProp in window',
        'someObject.secondProp in window',
        'someObject.undefinedProp in window',
        'notDefined in window',

        '"definedButNotInitialized" in window',
        '"definedAndInitialized" in window',
        '"someObject.firstProp" in window',
        '"someObject.secondProp" in window',
        '"someObject.undefinedProp" in window',
        '"notDefined" in window',

        'typeof definedButNotInitialized == "undefined"',
        'typeof definedButNotInitialized === typeof undefined',
        'definedButNotInitialized === undefined',
        '! definedButNotInitialized',
        '!! definedButNotInitialized',

        'typeof definedAndInitialized == "undefined"',
        'typeof definedAndInitialized === typeof undefined',
        'definedAndInitialized === undefined',
        '! definedAndInitialized',
        '!! definedAndInitialized',

        'typeof someObject.firstProp == "undefined"',
        'typeof someObject.firstProp === typeof undefined',
        'someObject.firstProp === undefined',
        '! someObject.firstProp',
        '!! someObject.firstProp',

        'typeof someObject.secondProp == "undefined"',
        'typeof someObject.secondProp === typeof undefined',
        'someObject.secondProp === undefined',
        '! someObject.secondProp',
        '!! someObject.secondProp',

        'typeof someObject.undefinedProp == "undefined"',
        'typeof someObject.undefinedProp === typeof undefined',
        'someObject.undefinedProp === undefined',
        '! someObject.undefinedProp',
        '!! someObject.undefinedProp',

        'typeof notDefined == "undefined"',
        'typeof notDefined === typeof undefined',
        'notDefined === undefined',
        '! notDefined',
        '!! notDefined'
    ];

    var output = document.getElementById('results');
    var result = '';
    for(var t in tests) {
        if( !tests.hasOwnProperty(t) ) continue; // bleh

        try {
            result = eval(tests[t]);
        } catch(ex) {
            result = 'Exception--' + ex;
        }
        console.log(tests[t], result);
        output.innerHTML += "\n" + tests[t] + ": " + result;
    }
})();

和结果:

definedButNotInitialized in window: true
definedAndInitialized in window: false
someObject.firstProp in window: false
someObject.secondProp in window: false
someObject.undefinedProp in window: true
notDefined in window: Exception--ReferenceError: notDefined is not defined
"definedButNotInitialized" in window: false
"definedAndInitialized" in window: true
"someObject.firstProp" in window: false
"someObject.secondProp" in window: false
"someObject.undefinedProp" in window: false
"notDefined" in window: false
typeof definedButNotInitialized == "undefined": true
typeof definedButNotInitialized === typeof undefined: true
definedButNotInitialized === undefined: true
! definedButNotInitialized: true
!! definedButNotInitialized: false
typeof definedAndInitialized == "undefined": false
typeof definedAndInitialized === typeof undefined: false
definedAndInitialized === undefined: false
! definedAndInitialized: false
!! definedAndInitialized: true
typeof someObject.firstProp == "undefined": false
typeof someObject.firstProp === typeof undefined: false
someObject.firstProp === undefined: false
! someObject.firstProp: false
!! someObject.firstProp: true
typeof someObject.secondProp == "undefined": false
typeof someObject.secondProp === typeof undefined: false
someObject.secondProp === undefined: false
! someObject.secondProp: true
!! someObject.secondProp: false
typeof someObject.undefinedProp == "undefined": true
typeof someObject.undefinedProp === typeof undefined: true
someObject.undefinedProp === undefined: true
! someObject.undefinedProp: true
!! someObject.undefinedProp: false
typeof notDefined == "undefined": true
typeof notDefined === typeof undefined: true
notDefined === undefined: Exception--ReferenceError: notDefined is not defined
! notDefined: Exception--ReferenceError: notDefined is not defined
!! notDefined: Exception--ReferenceError: notDefined is not defined

C
Codebeat

如果你这样做

if (myvar == undefined )
{ 
    alert('var does not exists or is not initialized');
}

当变量 myvar 不存在时会失败,因为 myvar 没有定义,所以脚本坏了,测试没有效果。

因为窗口对象在函数之外具有全局范围(默认对象),所以声明将“附加”到窗口对象。

例如:

var myvar = 'test';

全局变量 myvar 与 window.myvar 或 window['myvar'] 相同

为避免在全局变量存在时测试错误,您最好使用:

if(window.myvar == undefined )
{ 
    alert('var does not exists or is not initialized');
}

变量是否真的存在的问题并不重要,它的值是不正确的。否则用 undefined 初始化变量是愚蠢的,最好使用值 false 来初始化。当您知道您声明的所有变量都以 false 初始化时,您可以简单地检查其类型或依靠 !window.myvar 来检查它是否具有正确/有效的值。因此,即使未定义变量,!window.myvar 对于 myvar = undefinedmyvar = falsemyvar = 0 也是相同的。

当您期望特定类型时,请测试变量的类型。为了加快测试条件,您最好执行以下操作:

if( !window.myvar || typeof window.myvar != 'string' )
{
    alert('var does not exists or is not type of string');
}

当第一个简单条件为真时,解释器跳过下一个测试。

最好使用变量的实例/对象来检查它是否获得了有效值。它更稳定,是一种更好的编程方式。

(y)


P
Peter Mortensen

在文章 Exploring the Abyss of Null and Undefined in JavaScript 中,我读到像 Underscore.js 这样的框架使用这个函数:

function isUndefined(obj){
    return obj === void 0;
}

void 0 只是编写 undefined 的一种简短方式(因为这是 void 后跟任何表达式返回的内容),它节省了 3 个字符。它也可以做var a; return obj === a;,但这是另外一个字符。 :-)
void 是保留字,而undefined 不是,即默认情况下undefined 等于void 0,您可以为undefined 赋值,例如undefined = 1234
isUndefined(obj):16 个字符。 obj === void 0:14 个字符。 '不够说。
A
Alireza

简单来说,任何东西都没有在 JavaScript 中定义,是未定义的,不管它是对象/数组中的属性还是只是一个简单的变量......

JavaScript 有 typeof,它可以很容易地检测未定义的变量。

只需检查 typeof whatever === 'undefined' 是否会返回一个布尔值。

这就是 AngularJs v.1x 中著名的函数 isUndefined() 的编写方式:

function isUndefined(value) {return typeof value === 'undefined';} 

因此,当您看到函数接收一个值时,如果该值已定义,它将返回 false,否则对于未定义的值,返回 true

所以让我们看看当我们传递值时会产生什么结果,包括像下面这样的对象属性,这是我们拥有的变量列表:

var stackoverflow = {};
stackoverflow.javascipt = 'javascript';
var today;
var self = this;
var num = 8;
var list = [1, 2, 3, 4, 5];
var y = null;

我们检查它们如下,您可以在它们前面看到结果作为评论:

isUndefined(stackoverflow); //false
isUndefined(stackoverflow.javascipt); //false
isUndefined(today); //true
isUndefined(self); //false
isUndefined(num); //false
isUndefined(list); //false
isUndefined(y); //false
isUndefined(stackoverflow.java); //true
isUndefined(stackoverflow.php); //true
isUndefined(stackoverflow && stackoverflow.css); //true

如您所见,我们可以在代码中使用类似这样的内容来检查任何内容,如前所述,您可以在代码中简单地使用 typeof,但如果您一遍又一遍地使用它,请创建一个函数,如我分享的 angular 示例和按照 DRY 代码模式继续重用。

还有一件事,要在实际应用程序中检查对象的属性,您甚至不确定该对象是否存在,请先检查该对象是否存在。

如果您检查对象的属性并且该对象不存在,则会抛出错误并停止整个应用程序的运行。

isUndefined(x.css);
VM808:2 Uncaught ReferenceError: x is not defined(…)

如此简单,您可以在 if 语句中包含如下内容:

if(typeof x !== 'undefined') {
  //do something
}

这也等于 Angular 1.x 中的 isDefined ...

function isDefined(value) {return typeof value !== 'undefined';}

下划线等其他 javascript 框架也有类似的定义检查,但如果您还没有使用任何框架,我建议您使用 typeof

我还添加了来自 MDN 的这一部分,其中包含有关 typeof、undefined 和 void(0) 的有用信息。

严格相等和未定义 您可以使用 undefined 以及严格相等和不等运算符来确定变量是否具有值。在以下代码中,未定义变量 x,并且 if 语句的计算结果为 true。

var x;
if (x === undefined) {
   // these statements execute
}
else {
   // these statements do not execute
}

注意:这里必须使用严格相等运算符而不是标准相等运算符,因为 x == undefined 也会检查 x 是否为空,而严格相等则不会。 null 不等于未定义。有关详细信息,请参阅比较运算符。

typeof 运算符和 undefined 或者,可以使用 typeof:

var x;
if (typeof x === 'undefined') {
   // these statements execute
}

使用 typeof 的一个原因是,如果尚未声明变量,它不会引发错误。

// x has not been declared before
if (typeof x === 'undefined') { // evaluates to true without errors
   // these statements execute
}

if (x === undefined) { // throws a ReferenceError

}

但是,应该避免这种技术。 JavaScript 是一种静态范围的语言,因此可以通过查看变量是否在封闭上下文中声明来了解变量是否已声明。唯一的例外是全局作用域,但全局作用域绑定到全局对象,因此可以通过检查全局对象上是否存在属性来检查全局上下文中的变量是否存在(使用 in 运算符,例如)。

void 运算符和 undefined void 运算符是第三种选择。

var x;
if (x === void 0) {
   // these statements execute
}

// y has not been declared before
if (y === void 0) {
   // throws a ReferenceError (in contrast to `typeof`)
}

更多> here


P
Peter Mortensen

ECMAScript 10 引入了一项新功能 - 可选链接,仅当对象定义如下时,您才能使用该功能使用对象的属性:

const userPhone = user?.contactDetails?.phone;

只有在定义了 user 和 contactDetails 时,它才会引用 phone 属性。

参考。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining


我以前用过很多lodash的get函数,访问这类对象很方便,但是新的可选链覆盖了_.get的大部分用法
这就是问题的答案。
P
Peter Mortensen

'if (window.x) { }' 是错误安全的

您很可能需要 if (window.x)。即使未声明 x (var x;),此检查也是安全的 - 浏览器不会引发错误。

示例:我想知道我的浏览器是否支持 History API

if (window.history) {
    history.call_some_function();
}

这是如何工作的:

window 是一个将所有全局变量作为其成员的对象,尝试访问不存在的成员是合法的。如果 x 尚未声明或尚未设置,则 window.x 返回 undefined。当 if() 评估它时,undefined 会导致 false


但是如果你在 Node 中运行呢? typeof history != 'undefined' 实际上适用于两个系统。
T
Travis

读到这里,我很惊讶我没有看到这个。我发现了多种适用于此的算法。

从未定义

如果从未定义过对象的值,如果将其定义为 nullundefined,这将阻止返回 true。如果您希望为设置为 undefined 的值返回 true,这将很有帮助

if(obj.prop === void 0) console.log("The value has never been defined");

定义为未定义或从未定义

如果您希望它对于使用 undefined 的值定义或从未定义的值作为 true,您可以简单地使用 === undefined

if(obj.prop === undefined) console.log("The value is defined as undefined, or never defined");

定义为假值、未定义、空值或从未定义。

通常,人们要求我提供一种算法来确定一个值是假的、undefined 还是 null。以下作品。

if(obj.prop == false || obj.prop === null || obj.prop === undefined) {
    console.log("The value is falsy, null, or undefined");
}

我认为您可以将最后一个示例替换为 if (!obj.prop)
@StijndeWitt,你可以,我写这篇文章的时候还很缺乏经验,而且我的英语似乎也同样糟糕,不过,答案中没有任何不正确的地方
var obj = {foo: undefined}; obj.foo === void 0 -> true。那“从未定义为undefined”如何?这是错误的。
@PatrickRoberts 你是对的。当我在 2015 年 2 月(在 ES6 之前)写这个答案时,我概述的第一个选项确实有效,但它现在已经过时了。
s
sam
"propertyName" in obj //-> true | false

P
Peter Mortensen

解决方案不正确。在 JavaScript 中,

null == undefined

将返回 true,因为它们都被“强制转换”为布尔值并且为 false。正确的方法是检查

if (something === undefined)

这是身份运算符...


需要明确的是,=== 是类型相等 +(原始相等 | 对象标识),其中原始包含字符串。如果将 === 视为身份运算符,我认为大多数人认为 'abab'.slice(0,2) === 'abab'.slice(2) 不直观。
错误的。如果尚未创建变量,则会引发错误。不应该投赞成票。改用 typeof。
什么解决方案?可以直接链接吗?
b
bevacqua

为了简洁起见,与 void 0 进行比较。

if (foo !== void 0)

它不像 if (typeof foo !== 'undefined') 那样冗长


但如果 foo 未声明,它将引发 ReferenceError。
@daniel1426:所以如果你的代码有错误,你想隐藏它而不是修复它? IMO,这不是一个好方法。
这不用于隐藏错误。这是检测环境属性以定义 polyfill 的常用方法。例如: if( typeof Promise === 'undefined' ){ /* 定义 Promise */ }
P
Peter Mortensen

您可以使用以下代码获取所有未定义路径的数组。

 function getAllUndefined(object) {

        function convertPath(arr, key) {
            var path = "";
            for (var i = 1; i < arr.length; i++) {

                path += arr[i] + "->";
            }
            path += key;
            return path;
        }


        var stack = [];
        var saveUndefined= [];
        function getUndefiend(obj, key) {

            var t = typeof obj;
            switch (t) {
                case "object":
                    if (t === null) {
                        return false;
                    }
                    break;
                case "string":
                case "number":
                case "boolean":
                case "null":
                    return false;
                default:
                    return true;
            }
            stack.push(key);
            for (k in obj) {
                if (obj.hasOwnProperty(k)) {
                    v = getUndefiend(obj[k], k);
                    if (v) {
                        saveUndefined.push(convertPath(stack, k));
                    }
                }
            }
            stack.pop();

        }

        getUndefiend({
            "": object
        }, "");
        return saveUndefined;
    }

jsFiddle 链接


虽然它不会影响您的代码的有效性,但您有一个错字:getUndefiend 应该是 getUndefined
P
Peter Mortensen

如果已定义新变量,则有一种很好且优雅的方法可以将已定义属性分配给新变量,如果未定义,则将默认值分配给它作为后备。

var a = obj.prop || defaultValue;

如果您有一个接收附加配置属性的函数,则它是合适的:

var yourFunction = function(config){

   this.config = config || {};
   this.yourConfigValue = config.yourConfigValue || 1;
   console.log(this.yourConfigValue);
}

现在执行

yourFunction({yourConfigValue:2});
//=> 2

yourFunction();
//=> 1

yourFunction({otherProperty:5});
//=> 1

使用 || (OR) 将对“未定义”和“空”值使用类型强制转换为 false,并将所有其他值转换为“true”。 ------- 如果检查的属性(例如“obj.prop”和“config”)未定义或为空,它将被分配“默认值”。在任何其他情况下,该值都不会改变。 -------- 这个灵魂不检查对象是否定义了属性。 - - - - - - - - - - - - - - - - - - - - - - - - 去检查如果对象具有您可以使用的属性:let objAndPropCheck = (obj || { }).prop || 0;
P
Peter Mortensen

所有的答案都不完整。这是知道有一个属性“定义为未定义”的正确方法:

var hasUndefinedProperty = function hasUndefinedProperty(obj, prop){
  return ((prop in obj) && (typeof obj[prop] == 'undefined'));
};

例子:

var a = { b : 1, e : null };
a.c = a.d;

hasUndefinedProperty(a, 'b'); // false: b is defined as 1
hasUndefinedProperty(a, 'c'); // true: c is defined as undefined
hasUndefinedProperty(a, 'd'); // false: d is undefined
hasUndefinedProperty(a, 'e'); // false: e is defined as null

// And now...
delete a.c ;
hasUndefinedProperty(a, 'c'); // false: c is undefined

太糟糕了,这是正确的答案,却被错误的答案所掩盖>_<

所以,任何路过的人,我都会免费给你undefined的!!

var undefined ; undefined ; // undefined
({}).a ;                    // undefined
[].a ;                      // undefined
''.a ;                      // undefined
(function(){}()) ;          // undefined
void(0) ;                   // undefined
eval() ;                    // undefined
1..a ;                      // undefined
/a/.a ;                     // undefined
(true).a ;                  // undefined

P
Peter Mortensen

这是我的情况:

我正在使用 REST 调用的结果。结果应从 JSON 解析为 JavaScript 对象。

我需要捍卫一个错误。如果 REST 调用的参数不正确,就用户指定的参数错误而言,REST 调用返回基本上是空的。

在使用这篇文章来帮助我防御这一点时,我尝试了这个:

if( typeof restResult.data[0] === "undefined" ) { throw  "Some error"; }

对于我的情况,如果 restResult.data[0] === "object",那么我可以安全地开始检查其余成员。如果未定义,则抛出上述错误。

我要说的是,就我的情况而言,这篇文章中之前的所有建议都不起作用。我不是说我是对的,每个人都是错的。我根本不是 JavaScript 大师,但希望这会对某人有所帮助。


您的 typeof 守卫实际上并没有防范直接比较无法处理的任何事情。如果 restResult 未定义或未声明,它仍然会抛出。
在您的情况下,您可以更简单地检查数组是否为空:if(!restResult.data.length) { throw "Some error"; }
P
Peter Mortensen

浏览评论,对于那些想要同时检查的人是未定义还是它的值为空:

//Just in JavaScript
var s; // Undefined
if (typeof s == "undefined" || s === null){
    alert('either it is undefined or value is null')
}

如果您使用的是 jQuery 库,那么 jQuery.isEmptyObject() 对于这两种情况都足够了,

var s; // Undefined
jQuery.isEmptyObject(s); // Will return true;

s = null; // Defined as null
jQuery.isEmptyObject(s); // Will return true;

//Usage
if (jQuery.isEmptyObject(s)) {
    alert('Either variable:s is undefined or its value is null');
} else {
     alert('variable:s has value ' + s);
}

s = 'something'; // Defined with some value
jQuery.isEmptyObject(s); // Will return false;

jQuery 还将处理不同 JavaScript API 的任何跨浏览器兼容性问题。
V
Vitalii Fedorenko

如果您使用的是 Angular:

angular.isUndefined(obj)
angular.isUndefined(obj.prop)

下划线.js:

_.isUndefined(obj) 
_.isUndefined(obj.prop) 

如何将 1 添加到变量 x?我需要下划线还是 jQuery? (令人惊讶的是,即使是最基本的操作,例如 typeof 检查,人们也会使用库)
P
Peter Mortensen

我在这里为那些期待奇怪答案的人提供了三种方法:

函数 isUndefined1(val) { 尝试 { val.a; } catch (e) { return /undefined/.test(e.message); } 返回假; } function isUndefined2(val) { return !val && val+'' === 'undefined'; } function isUndefined3(val) { const defaultVal = {};返回 ((输入 = defaultVal) => 输入 === defaultVal)(val); } function test(func){ console.group(`test start :`+func.name); console.log(func(undefined));控制台.log(func(null));控制台.log(func(1)); console.log(func("1")); console.log(func(0)); console.log(func({})); console.log(func(function () { }));控制台.groupEnd(); } 测试(isUndefined1);测试(isUndefined2);测试(isUndefined3);

未定义1:

尝试获取输入值的属性,并检查错误消息是否存在。如果输入值未定义,则错误消息将是 Uncaught TypeError: Cannot read property 'b' of undefined。

未定义2:

将输入值转换为字符串以与 "undefined" 进行比较并确保它是负值。

未定义3:

在 JavaScript 中,当输入值正好是 undefined 时,可选参数起作用。


u
user1527225

有一个非常简单的方法。

您可以使用可选链接:

x = {prop:{name:"sajad"}}

console.log(x.prop?.name) // Output is: "sajad"
console.log(x.prop?.lastName) // Output is: undefined

或者

if(x.prop?.lastName) // The result of this 'if' statement is false and is not throwing an error

您甚至可以对函数或数组使用可选链接。

截至 2020 年中期,这并未普遍实施。查看 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining 处的文档


这正是我一直在寻找的。谢谢!
P
Peter Mortensen

我使用 if (this.variable) 来测试它是否已定义。一个简单的 if (variable)recommended in a previous answer,对我来说失败了。

事实证明,它仅在变量是某个对象的字段时才起作用,obj.someField 检查它是否在字典中定义。但是我们可以使用 thiswindow 作为字典对象,因为据我所知,任何变量都是当前窗口中的一个字段。因此这里是一个测试:

如果(this.abc)警报(“定义”);否则警报(“未定义”); abc = "abc";如果(this.abc)警报(“定义”);否则警报(“未定义”);

它首先检测到变量 abc 是未定义的,它是在初始化之后定义的。


S
Simon East
function isUnset(inp) {
  return (typeof inp === 'undefined')
}

如果设置了变量,则返回 false,如果未定义,则返回 true。

然后使用:

if (isUnset(var)) {
  // initialize variable here
}

不,不要这样做。只需要 very simple test 即可证明您无法将 typeof 测试有意义地包装在函数中。令人惊讶的是,有 4 人对此表示赞同。 -1。
P
Peter Mortensen

我想向您展示我正在使用的东西来保护 undefined 变量:

Object.defineProperty(window, 'undefined', {});

这禁止任何人更改 window.undefined 值,从而破坏基于该变量的代码。如果使用 "use strict",任何试图改变它的值的东西都会出错,否则它会被忽略。