前言

今日,在阅读 vant 组件源码时,发现了这样的语句:

1
var _createNamespace = (0, _utils.createNamespace)('radio')

偶尔也会在其他一些地方见到类似的,如 webpack4 源码中有

1
var test2 = (0, _test2.default)();

抽象一下

1
(0, function)();

提问:这个语法的结果是什么?使用这个语法的意义又是什么?

一、逗号操作符

MDN 上对”逗号操作符”的解释为对它的每个操作数求值(从左到右),并返回最后一个操作数的值。

1.1. 使用场景

大致上,需要用到逗号操作符大致有下面两种情况:

  1. 当你想要在期望一个表达式的位置包含多个表达式时,可以使用逗号操作符。

    举例来说,

    1
    2
    3
    // 多变量循环
    for (var i = 0, j = 9; i <= 9; i++, j--)
    document.writeln("a[" + i + "][" + j + "] = " + a[i][j]);

    上例中,i++, j-- 这个部分应用了逗号操作符。

  2. 另一个使用逗号操作符的例子是在返回值前处理一些操作。

    举例来说,

    1
    2
    3
    4
    function myFunc () {
    var x = 0;
    return (x += 1, x); // 同 return ++x;
    }

    这里的 (x += 1, x) 便是对逗号操作符的应用:先执行语句 x += 1,再执行语句 x ,最后返回语句 x 的执行结果,即值 x

注意:逗号操作符只返回最后一个语句执行结果。前面的只执行,不返回

二、(0, function)();

很明显,(0, function)(); 这个语句就是使用了逗号操作符。

当然,我们也可以写(true, function)(); 或者 (1, function)();,都是一个意思:取出 function 并执行。

那么,为什么要用这种方式执行 function 呢?直接调用不行么?

如果只是简单的

1
2
3
4
function fun() {
console.log(this);
}
(0, function)();

这样使用是没有意义的,等同于直接调用 function

那,如果我们这样写:

1
2
3
4
const obj = {
fun() { console.log(this); }
}
(0, obj.fun)();

上面这串代码,我们用 node 执行,输出 global 对象;在浏览器执行,输出 window 对象。

如果我们像这样 obj.func(); 直接执行,得到的就会是 obj 对象了。

如此,我们得出结论:

(0, function)(); 可以让 functionthis 指向全局对象(严格模式下指向 undefined)。

实际上,无论是 vant 还是 webpack4 都是这种用法,而且 objrequire 的模块对象。如 vant 中,有

1
2
3
var _utils = require("../utils");
...
var _createNamespace = (0, _utils.createNamespace)('radio')

如果直接调用 _utils.createNamespace,那么方法内的 this 必定指向 _utils 这个对象,不能满足要求。


[参考]

  1. [MDN-逗号操作符] (https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Comma_Operator)
  2. Why does babel rewrite imported function call to (0, fn)(…)?