JavaScript中undefined和未定义的区别

29

查看http://jsfiddle.net/FDhQF/1/以获得一个微不足道的示例。

在Javascript中,未定义(undefined)和未被定义(not being defined)之间有什么区别?例如,尝试访问一个未定义的对象属性(本质上是尝试访问一个变量)将返回undefined。但是您也可以设置某些内容= undefined。当您这样做时,尝试访问它仍将返回undefined,但指针仍然存在。如上所述的示例,迭代对象仍会遍历您已(重新)声明为未定义的属性。看起来有两种不同类型的未定义情况。是否有人能够阐明一下这种情况?

2个回答

49

访问一个对象上未定义的属性和包含原始值undefined的属性都将返回undefined

例如:

var obj = {
  a: undefined
};

obj.a; // undefined
obj.b; // undefined

区别在于a是自有属性,而b不是:

obj.hasOwnProperty('a'); // true
obj.hasOwnProperty('b'); // false

在第一个例子中,即使它的值为undefined,a是一个自有属性。在第二个例子中,b不是一个自有属性,访问obj.b将会查找原型链上名为b的属性。
当原型链结束时(当它到达具有null [[Prototype]]的对象时),属性查找结束并明确返回undefined
你应该知道hasOwnProperty方法仅检查属性是否在对象上物理存在(自有属性),但我们也有继承属性,对于这种情况,我们可以使用in操作符,例如:
function Test () {}
Test.prototype.a = 'foo'; // instances of Test will inherit from Test.prototype

var obj = new Test(); // { a="foo",  b="bar"}
obj.b = 'bar';

obj.hasOwnProperty('a');  // false
'a' in obj;               // true
obj.a;                    // 'foo'

obj.hasOwnProperty('b');  // true

正如您所看到的,obj继承自Test.prototypea属性不是一个自有属性,但是它可以通过原型链访问。这就是为什么hasOwnProperty返回false,而in运算符返回true
您可以看到内部属性是如何通过[[Get]]内部操作解析的。 注:
  • 在ECMAScript 3(语言标准的最广泛实现版本)中,将undefined作为标识符访问被认为是不安全的,因为它不是语言关键字(例如null),只是全局对象的属性,在此版本的规范中可写,这意味着如果有人替换它的值(例如window.undefined = 'LOL';),它会破坏您的代码。
可以使用typeof运算符,例如:
if (typeof obj.prop == 'undefined') { /*....*/ }

这个操作符始终返回一个字符串(可以安全地使用 == :)),其值取决于其操作数的类型,可能的值在这里描述。
另一种常见的解决方法是声明自己的未定义变量,在函数作用域内可用,例如,一些库使用以下模式:
(function(undefined) {
  // code here
})();

该函数有一个名为undefined的参数,并且在没有传递任何值的情况下立即执行它(最后一对括号进行调用)。
也许值得一提的是undefined全局属性最终被描述为不可写(不可变,同时也不可枚举和不可配置-不可删除-)在ECMAScript 5中。
  • Using the hasOwnProperty method directly from an object instance is also not considered as safe, because if some object has a property with the same name, the original method will be shadowed. For example:

    var obj = { hasOwnProperty: function () { /* evil code :) */ } };
    
如果您调用:
    obj.hasOwnProperty('prop'); 

对象上定义的方法将被执行(而您不希望这样,因为您知道要调用哪个方法...),因为它遮蔽了来自Object.prototype的方法,但是可以通过以下方式安全地调用:

    Object.prototype.hasOwnProperty.call(obj, 'prop');

除了 .hasOwnProperty 之外,还有 in 运算符需要提及。 - strager
1
在你的第一个注意事项中,请指明要检查值是否未定义,请使用 typeof x === 'undefined'。另外,我不明白为什么 Object.prototype.hasOwnProperty 被认为是不安全的;我用它来达到你声称它不安全的相同目的。您能否在这一点上澄清一下? - strager
感谢您详细的回答,CMS。目前为止,我仍然看不出JavaScript对undefined的实现相比于更传统的“抛出异常”或“返回nil/null”方法有何优势,但是您的回答确实有助于阐明这种情况。 - Steven
@Steven Xu,我个人希望在访问未定义的属性时会抛出异常,但这样会阻止像JavaScript中我非常喜欢的x = foo.bar || default;这样简单的速记法。 - strager

1

这里是“未定义”一个很好的解释。但要点是,将某物设为“undefined”并不意味着取消定义,因为“undefined”实际上是一种原始值,当变量(或属性)没有被赋值时使用。


undefined 实际上是一个最初设置为原始值的变量。例如,在没有显式返回值的函数中返回时,使用的是原始值而不是变量。 - strager
1
此外,您提供的链接似乎没有直接回答问题。 - strager

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接