目录

  1. void 是什么?
  2. void 的作用
    1. JavaScript URIs
    2. 立即调用的函数表达式
    3. 在箭头函数中避免泄漏
  3. void 优先级
  4. void 的执行
  5. 为什么要用 void ?

    前言

前两天在开发项目的公共基础库时,无意间在看 moment.js 源代码的时候发现这样一个 util 函数。这个函数作用无非就是判断输入否是 undefined ,这个不是关键,关键是 void 这个引起了我的注意,这里为什么不直接使用 input === undefined ?而是使用这种形式来判断了。带着疑问我们今天就一起来看看 JavaScript void 运算符。

  1. export default function isUndefined(input) {
  2. return input === void 0;
  3. }

1. void 是什么?

void 运算符 对给定的表达式进行求值,然后返回 undefined。语法就是 void _expression 。_void 是一个一元运算符,它可以出现在任意类型的操作数之前执行操作数,却忽略操作数的返回值,返回一个 undefined。void 在表达式的左边,void 右边的表达式可以是带括号形式(例如:void(0)),也可以是不带括号的形式(例如:void 0)。

2. void 的作用

1. JavaScript URIs

如果有印象的同学是不是会发现,我们在阻止 a 标签的默认事件是会用到这个。

  1. <a href="javascript:void(0);">
  1. <a href="javascript:void(0);">
  2. 这个链接点击之后不会做任何事情,如果去掉 void(),
  3. 点击之后整个页面会被替换成一个字符 0。
  4. </a>
  5. <p>
  6. chrome中即使<a href="javascript:0;">也没变化,firefox中会变成一个字符串0
  7. </p>
  8. <a href="javascript:void(document.body.style.backgroundColor='green');">
  9. 点击这个链接会让页面背景变成绿色。
  10. </a>

注意,虽然这么做是可行的,但利用 javascript: 伪协议来执行 JavaScript 代码是不推荐的,推荐的做法是为链接元素绑定事件。

2. 立即调用的函数表达式

在使用立即执行的函数表达式时,可以利用 void 运算符让 JavaScript 引擎把一个function关键字识别成函数表达式而不是函数声明(语句)。

  1. void function iife() {
  2. var bar = function () {};
  3. var baz = function () {};
  4. var foo = function () {
  5. bar();
  6. baz();
  7. };
  8. var biz = function () {};
  9. foo();
  10. biz();
  11. }();

3. 在箭头函数中避免泄漏

箭头函数标准中,允许在函数体不使用括号来直接返回值。 如果右侧调用了一个原本没有返回值的函数,其返回值改变后,则会导致非预期的副作用。 安全起见,当函数返回值是一个不会被使用到的时候,应该使用 void 运算符,来确保返回 undefined(如下方示例),这样,当 API 改变时,并不会影响箭头函数的行为。

  1. button.onclick = () => void doSomething();

确保了当 doSomething 的返回值从 undefined 变为 true 的时候,不会改变函数的行为。

3. void 优先级

由于 void 运算符的优先级比较高(14),高于普通运算符的优先级,所以在使用时应该使用小括号明确 void 运算符操作的操作数,避免引发错误。

在下面的示例代码中,由于第一行没有使用小括号,void 运算符优先计算,恒等于( void 2)- 1,也就是 undefined - 1,结果为 NaN,在第二行代码中用括号包含了 (2-1),所以优先于是先计算2-1,在处理 void,恒等于 void (1),结果也就是 undefined。

  1. console.log(void 2 - 1); //返回NaN
  2. console.log(void (2 - 1)); //返回undefined

4. void 的执行

image.png
在 262 ECMA 中,对 void 有一个执行步骤的解释,大致的解读一下:

  1. 执行 UnaryExpression 并把返回值赋值给 expr
  2. 调用 GetValue(expr)
  3. 返回 undefined

注意最后的一句话,GetValue一定要调用,即使它的值不会被用到,但是这个表达式可能有副作用。其实这个副作用是什么,并没有解释。既然void xx === undefined,我们回到最开始的问题,哪 void 0 、void 100、void xx()、void 不管什么操作,返回的都是 undefined 。哪为什么在 moment.js 中不直接写 input === undefined。

5. 为什么要用 void ?

我们知道 undefined 在 JavaScript 中是一个保留字。哪既然他是一个保留字,我们就可以为它赋值。

  1. function test() {
  2. var undefined = "不爱吃猫的鱼er";
  3. console.log(undefined); // 不爱吃猫的鱼er
  4. }
  5. test();
  6. console.log(undefined); // undefined

Kapture 2021-05-10 at 23.26.59.gif
赋值之后你提取到的 undefined 就不等于 undefined了,当然如果我们使用的是 window 对象上的 undefined,也可能被赋值 。所以你直接使用的 undefined ,不一定是100%可靠。于是在很多框架或者基础 JS 库中,采用void方式获取 undefined 便成了通用准则。例如 moment.js、Backbone.js、underscore.js,在他们的源码中对 undefined 的使用都是使用 void 0 代替。

  • moment.js

    1. export default function isUndefined(input) {
    2. return input === void 0;
    3. }
  • Backbone.js

    1. if (callback !== void 0 && 'context' in opts && opts.context === void 0) opts.context = callback;
  • underscore.js

    1. _.isUndefined = function(obj) {
    2. return obj === void 0;
    3. }

除了采用void能保证取到 undefined 值以外,AngularJS 的源码里通过函数调用不传参数,确保了 undefined 参数的值是一个 undefined

  1. (function(window, document, undefined) {
  2. //.....
  3. })(window, document);

总结

通过 void xx 这种方式来获取 undefined,比直接使用 undefined 来的更加可靠安全,所以在很多的库、框架中都使用 void xx 这种方式来处理undefined ,保证使用到的是安全可靠的 undefined。这种方式我们在日常的项目开发或者的封装也可以借鉴起来。

结束语

如果文章中什么不对或者写的不好的地方,请大家多多指正,谢谢!码字不易,点个赞加个关注吧!
靓仔.gif

参考