JavaScript中(0,someFunction)()的含义是什么?

70

我在某个人的代码中发现了这段代码,它长这样:

(0, function (arg) { ... })(this)

在我尝试以下操作之后:

(0, function (arg) { console.log(arg) })(2);
console.log((0, 1, 2, 3));
(0, function plus1 (arg) { console.log(arg + 1) }, function plus2 (arg) { console.log(arg + 2) })(5);

我发现它总是返回括号中的最后一个项目。

我想知道这种编程模式的名称和用例是什么?


85
这是“逗号操作符”,它可以让人们感到困惑,但也有其实用性。 - Ry-
1
是的,在那种情况下我看不出有任何实际的理由...... 0, 简直是毫无用处的。 - qxz
3
看起来这个人想要显得聪明,所以不是直接使用IIFE。 - Trash Can
17
“it’s useful for confusing people”的最佳描述。翻译:它可以用来混淆人们。 - Jaromanda X
2
而对于面试问题,或者为了让自己变得不可替代,因为没有人理解你的代码。 - Mawg says reinstate Monica
3个回答

76
在这种特定情况下,似乎有些多余,但有时这种方法很有用。
例如,在使用eval时:

(function() {
  (0,eval)("var foo = 123"); // indirect call to eval, creates global variable
})();
console.log(foo);            // 123
(function() {
  eval("var bar = 123");     // direct call to eval, creates local variable
})();
console.log(bar);            // ReferenceError

当您想调用一个方法而不将对象作为this值传递时,它也非常有用:

var obj = {
  method: function() { return this; }
};
console.log(obj.method() === obj);     // true
console.log((0,obj.method)() === obj); // false

需要注意的是,根据上下文,它可能是参数分隔符,而不是逗号运算符:

console.log(
  function(a, b) {
    return function() { return a; };
  }
  (0, function (arg) { /* ... */ })(this)
); // 0

在这种情况下,(0, function (arg) { /* ... */ })是传递给函数的参数(a=0, b=function (arg) { /* ... */ })。
function(a, b) {
  return function() { return a; };
}

建议使用逗号运算符之外的方式。(然后,末尾的(this)是对返回函数function() { return a; }传递参数this的函数调用。但这部分与逗号操作符/参数分隔符的区别无关)


20
你刚才给了我许多其他理由来证明JavaScript的设计存在问题。 - Bakuriu
3
如果您想在严格模式下实现相同的效果,应将代码更改为obj.method.call(undefined)。但这需要函数从Function.prototype继承call。并非所有callable对象都继承自Function.prototype,即使它们如此,call也可能被隐藏。 - Oriol
2
有人能解释为什么这个可以工作吗?看起来JavaScript会使用另一个函数包装函数引用,其第一个参数是作用域或上下文?你可以使用什么来替换0,使上述表达式再次成立? - latj
2
@latj obj.method 会产生一个引用,因此当你调用它时,基础的 obj 被用作 this 值。但是当你使用逗号运算符(无论你使用 0 还是其他什么)时,引用被解析为一个值。 - Oriol
eval表达式 (function() { (0, eval)("var foo = 123"); })(); 等同于 (function() { eval.call(this, "var bar = 123"); })(); - Danilo Gómez
显示剩余2条评论

3

3
典型的例子可能是:
for(var i=0,j=10; i < j; i++){
 // code ...
}

逗号运算符会从左到右依次计算表达式,并返回最右边的表达式的结果。

// e.g.

var a = 1, b= 2, c = 3, d = function(){ console.log("a => " +  a) }()


3
我认为 var a = 1, b = 2, c = 3 不是“逗号运算符”,而是一个变量声明。这里的 abc 都在局部作用域中创建,所以实际上都使用了 var 进行了声明。为了举例说明,这里有两个函数: function foo(){var a = 1, b = 2, c = 3;} function bar(){var a = (1, b = 2, c = 3);}如果你运行 foo();,那么 abc 只存在于局部作用域中。然而,如果你运行 bar();,你会发现 bc 存在于全局作用域中!这是因为 (1, b = 2, c = 3) 部分现在成为了“逗号运算符”。 - Joseph Shih
这是源代码: https://www.i-programmer.info/programming/javascript/6524-the-confusing-comma-in-javascript.html 在“这不是你要找的逗号”一节下。 - Joseph Shih
现在我明白了 - 我猜我需要把它和我已知的某些东西联系起来(在声明中使用逗号)。 - la Fleur

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