JS的细节——void运算符,变量undefined

992 阅读3分钟

一、背景介绍

最近得得知了一个在线ES6转ES5的网站,就把之前手写的call方法拿来试用了一下在线的babel

function jCall(thisArg, ...args) {
  // 转换前的ES6
  thisArg = thisArg ?? window
  ... ...
}
"use strict";

function jCall(thisArg) {
  var _thisArg, _thisArg2;
  // 转换后的ES5
  thisArg = (_thisArg = thisArg) !== null && _thisArg !== void 0 ? _thisArg : window;
  ... ...
}

二、提出问题

空值合并操作符(??)不是用来判断null和undefined么,void 0是什么鬼?_thisArg !== void 0 是啥意思?为啥这么写?带着这样的疑问,去上网查找各种资料,然后得到了答案。

三、void 运算符

3.1 void 运算符的理解

void 运算符 对给定的表达式进行求值,然后返回 undefined。 ——摘自MDN

在这里插入图片描述

根据测试我们可以得知void操作符不论右边的表达式是什么最后都会返回一个undefined,并且在返回undefined之前会正常执行右侧的表达式。

3.2 void 运算符的使用场景

根据以上特性我们可以在如下场景使用void 操作符。

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

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

onclick方法不需要接受任何的返回值,最初我们的doSomething也没有任何的返回值,但是有一天我们的doSomething根据要求做了改动有了返回值,onclick 就会接到一个意外的返回值,从而引起一些问题的出现。这时我们就可以使用void 操作符,来确保onclick方法一直返回undefined。

看到这里有的人可能就会问了,这和上边的转换成ES5也没啥大关系啊,我直接用_thisArg !== undefined 多好啊,为啥非要用 void 0,让人一脸懵?这里我们就需要来说说JS中的一个细节问题了,这也是我这次翻阅资料的一个重要的收获!!!

四、变量undefined

全局属性undefined表示原始值undefined。它是一个JavaScript的 原始数据类型 。 ——摘自MDN

JS中undefined是全局对象的一个只读属性,或者说是全局作用域中的一个变量,这个属性(变量)的值是JS的原始数据类型undefined。 在这里插入图片描述

神奇的是我们可以在函数作用域等非全局作用域下对undefined进行重写,声明一个变量名为undefined的变量,因为undefined不是一个保留字在这里插入图片描述

所以这就是为什么转换后的ES5中用void 0 来代替undefined的原因。

这也是这一节的标题叫做变量undefined,而不是关键字undefined的原因。

到这里可能有的小伙伴会问为什么是void 0 不是void 'hello' 等其他的void表达式呢,不也可以返回undefined么?

这就要提到另外一个使用void 0 的原因了,相比较于undefined的,void 0占用的字节更少。所以我们会选用void 0。事实上,很多的JS压缩工具都会用void 0来代替undefined

五、总结

通过这次对在线bebel的尝试,让我对JS的细节有了更多的了解

  1. void 运算符 对给定的表达式进行求值,然后返回 undefined。
  2. undefined是变量,不是一个关键字,在非全局下可以重新声明并且赋值。

一个出自js小白的学习记录,不对的地方欢迎指正。