"void 0" 和 "undefined" 的区别是什么?

66

我正在使用Closure Compiler,在编译我的脚本时我需要经历以下步骤:

编译前:

// ==ClosureCompiler==
// @compilation_level SIMPLE_OPTIMIZATIONS
// @output_file_name default.js
// @formatting pretty_print,print_input_delimiter
// ==/ClosureCompiler==

var myObj1 = (function() {

  var undefined;   //<----- declare undefined

  this.test = function(value, arg1) {

    var exp = 0;
    arg1 = arg1 == undefined ? true : arg1;  //<----- use declare undefined
    exp = (arg1) ? value * 5 :  value * 10;

    return exp;
  };

  return this;
}).call({});

var myObj2 = (function() {

  this.test = function(value, arg1) {

    var exp = 0;
    arg1 = arg1 == undefined ? true : arg1;  //<----- without declare undefined
    exp = (arg1) ? value * 5 :  value * 10;

    return exp;
  };

  return this;
}).call({});

已编译:

// Input 0
var myObj1 = function() {
  this.test = function(b, a) {
    a = a == void 0 ? true : a;  //<-----
    var c = 0;
    return c = a ? b * 5 : b * 10
  };
  return this
}.call({}), myObj2 = function() {
  this.test = function(b, a) {
    a = a == undefined ? true : a; //<-----
    var c = 0;
    return c = a ? b * 5 : b * 10
  };
  return this
}.call({});

我认为这个问题是关于使用 "void 0" 和 "undefined" 是否有区别,还是两种情况都可以的问题。

编辑

如果我定义了 "var undefined" 并且编译时使用了 "void 0",如果我没有定义 "undefined" 则编译时使用 "undefined"。这与 "undefined" 和 "void 0" 之间的字符数量无关。

测试

编辑 II:基于这个链接的性能

代码和测试

IE 8:
typeof: 228ms
undefined: 62ms
void 0: 57ms

Firefox 3.6:
typeof: 10ms
undefined: 3ms
void 0: 3ms

Opera 11:
typeof: 67ms
undefined: 19ms
void 0: 20ms

Chrome 8:
typeof: 3ms
undefined: 5ms
void 0: 3ms

4个回答

75

来自 MDN:

void 运算符会计算给定的 expression,并返回 undefined

该运算符允许将产生副作用的表达式插入到需要求值为 undefined 的表达式的位置。

void 运算符通常被用于仅获取原始值 undefined,通常使用“void(0)”(等同于“void 0”)实现。在这些情况下,可以使用全局变量 undefined(假设它没有被赋予非默认值)。

Closure Compiler 使用 void 0 代替 undefined,因为前者比后者更短,从而生成相等且更小的代码


回复 OP 评论:

是的,我阅读了文档,但在我提供的示例中,“Google Closure”在一种情况下使用“void 0”,在另一种情况下使用“undefined”

我认为这实际上是 Google Closure Compiler 中的一个 bug


1
是的,我阅读了文档,但在我提供的例子中,“google closure”在一个案例中使用“void 0”,另一个案例中使用“undefined”。 - andres descalzo
2
请查看@jAndy的文章,非常有趣。http://typeofnan.blogspot.com/2011/01/typeof-is-fast.html - andres descalzo
[][0] 是另一种选择。 - PuiMan Cheui

56

void exprundefined 之间唯一的语义差别是,在 ECMAScript3 中,全局对象的 undefined 属性(在浏览器环境中为 window.undefined)是可写的,而 void 运算符将始终返回 undefined 值。

通常实现的一种流行模式,可以放心地使用 undefined,只需声明一个参数,然后不传递任何内容即可:

(function (undefined) {
  //...
  if (foo !== undefined) {
    // ...
  }

})();

这将允许缩小参数,甚至可能缩小到一个字母的程度(比如比void 0还要短 :), 例如:

(function (a) {
  //...
  if (foo !== a) {
    // ...
  }
})();

好的。谢谢你,我一直在想undefined值是不是一个属性。http://typeofnan.blogspot.com/2011/01/typeof-is-fast.html - jAndy
@jAndy,不错的文章,感谢提及;)顺便说一句,你可以添加一个针对void 0的测试,这可能很有趣... - Christian C. Salvadó
谢谢!我已经检查过了,void 0undefined表现要好得多,但仍然落后于缓存版本。 - jAndy
我认为如果你在任何非匿名和不立即调用的函数上使用这种方法,你会自找麻烦。如果有人使用参数调用它(在大多数情况下,传递额外的参数到一个函数并不影响行为,比如 alert('test', '2nd param ignored')),例如通过像 someFunc.apply(this, arguments) 这样的代码,你就有可能与完全不同的变量进行比较。我不会依赖这种技术来节省仅有的 5 个字符,而当 GZIP 压缩时,这些字符很可能会更少。 - Aidiakapi
CMS,但是 window.undefined = 0,但是assert(0!= undefined)。我有什么遗漏吗? - Alexander Suraphel
远离这个!你无法确定是否将变量传递给未定义,因为实际调用可能相隔数百行。虽然 foo !== undefined 可能仍然有效,但当你为 undefined 传入其他值时,像 foo === undefined 这样的测试会引发问题。 - huysentruitw

10

针对之前所有的回答进行一些跟进。

它们看起来相似,但对于编译器来说它们是完全不同的。

这两个代码段编译成不同的输出,因为一个引用了一个局部变量(var undefined),而编译器只是将其内联,因为它仅使用一次且不超过一行。如果它被使用多次,则这种内联不会发生。这种内联提供了“undefined”的结果,表示为“void 0”更短。

没有本地变量的那个引用了称为“undefined”的变量在全局对象下,这个变量由闭包编译器自动“外部化”(实际上,所有全局对象属性都是如此)。因此,不会进行重命名和内联。哇!仍然是“undefined”。


5

没有区别,你可以亲自尝试:

void 0 === undefined

将评估为true
undefined比预期多3个字符,我想这就是他们使用它的原因。


2
因此,这是一种带宽优化:通过传输更少的字节来减少带宽使用。 - Joel Coehoorn
1
@JoelCoehorn:嗯,闭包编译器也是一种代码压缩工具,我想他们在这里尽可能地挤压每一个字节。 - jAndy
如果我定义了“var undefined”,则编译时使用“void 0”,如果我没有定义“undefined”,则编译时使用“undefined”。因此,“undefined”和“void 0”之间的字符数量并不重要。 - andres descalzo
2
(function () { return 'foo' })() === 'foo' 也返回 true。这是否意味着两者之间没有区别? - Harry
2
@Harry,在代码中有很大的区别。但是经过评估,两边实际上都是“foo”字符串。未定义是void的结果。因此,即使在代码中void 0不同于undefined,它实际上会被评估为undefined,评估后它就是undefined。以同样的方式,我们说“2+2等于4”。是的,“2+2”不是4,它被评估为4,但在评估后它确实是4! - FrancescoMM
如果未定义未被重新定义,则没有区别。但这并不总是一个安全的假设。 - Steve Bennett

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