目录
前两天在开发项目的公共基础库时,无意间在看 moment.js 源代码的时候发现这样一个 util 函数。这个函数作用无非就是判断输入否是 undefined ,这个不是关键,关键是 void 这个引起了我的注意,这里为什么不直接使用 input === undefined ?而是使用这种形式来判断了。带着疑问我们今天就一起来看看 JavaScript void 运算符。
export default function isUndefined(input) {
return input === void 0;
}
1. void 是什么?
void
运算符 对给定的表达式进行求值,然后返回 undefined
。语法就是 void _expression 。_void 是一个一元运算符,它可以出现在任意类型的操作数之前执行操作数,却忽略操作数的返回值,返回一个 undefined。void 在表达式的左边,void 右边的表达式可以是带括号形式(例如:void(0)),也可以是不带括号的形式(例如:void 0)。
2. void 的作用
1. JavaScript URIs
如果有印象的同学是不是会发现,我们在阻止 a 标签的默认事件是会用到这个。
<a href="javascript:void(0);">
<a href="javascript:void(0);">
这个链接点击之后不会做任何事情,如果去掉 void(),
点击之后整个页面会被替换成一个字符 0。
</a>
<p>
chrome中即使<a href="javascript:0;">也没变化,firefox中会变成一个字符串0
</p>
<a href="javascript:void(document.body.style.backgroundColor='green');">
点击这个链接会让页面背景变成绿色。
</a>
注意,虽然这么做是可行的,但利用 javascript:
伪协议来执行 JavaScript 代码是不推荐的,推荐的做法是为链接元素绑定事件。
2. 立即调用的函数表达式
在使用立即执行的函数表达式时,可以利用 void
运算符让 JavaScript 引擎把一个function
关键字识别成函数表达式而不是函数声明(语句)。
void function iife() {
var bar = function () {};
var baz = function () {};
var foo = function () {
bar();
baz();
};
var biz = function () {};
foo();
biz();
}();
3. 在箭头函数中避免泄漏
箭头函数标准中,允许在函数体不使用括号来直接返回值。 如果右侧调用了一个原本没有返回值的函数,其返回值改变后,则会导致非预期的副作用。 安全起见,当函数返回值是一个不会被使用到的时候,应该使用 void
运算符,来确保返回 undefined
(如下方示例),这样,当 API 改变时,并不会影响箭头函数的行为。
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。
console.log(void 2 - 1); //返回NaN
console.log(void (2 - 1)); //返回undefined
4. void 的执行
在 262 ECMA 中,对 void 有一个执行步骤的解释,大致的解读一下:
- 执行 UnaryExpression 并把返回值赋值给 expr
- 调用 GetValue(expr)
- 返回 undefined
注意最后的一句话,GetValue一定要调用,即使它的值不会被用到,但是这个表达式可能有副作用。其实这个副作用是什么,并没有解释。既然void xx === undefined,我们回到最开始的问题,哪 void 0 、void 100、void xx()、void 不管什么操作,返回的都是 undefined 。哪为什么在 moment.js 中不直接写 input === undefined。
5. 为什么要用 void ?
我们知道 undefined 在 JavaScript 中是一个保留字。哪既然他是一个保留字,我们就可以为它赋值。
function test() {
var undefined = "不爱吃猫的鱼er";
console.log(undefined); // 不爱吃猫的鱼er
}
test();
console.log(undefined); // undefined
赋值之后你提取到的 undefined 就不等于 undefined了,当然如果我们使用的是 window 对象上的 undefined,也可能被赋值 。所以你直接使用的 undefined ,不一定是100%可靠。于是在很多框架或者基础 JS 库中,采用void
方式获取 undefined 便成了通用准则。例如 moment.js、Backbone.js、underscore.js,在他们的源码中对 undefined 的使用都是使用 void 0 代替。
moment.js
export default function isUndefined(input) {
return input === void 0;
}
Backbone.js
if (callback !== void 0 && 'context' in opts && opts.context === void 0) opts.context = callback;
underscore.js
_.isUndefined = function(obj) {
return obj === void 0;
}
除了采用void
能保证取到 undefined 值以外,AngularJS 的源码里通过函数调用不传参数,确保了 undefined 参数的值是一个 undefined。
(function(window, document, undefined) {
//.....
})(window, document);
总结
通过 void xx 这种方式来获取 undefined,比直接使用 undefined 来的更加可靠安全,所以在很多的库、框架中都使用 void xx 这种方式来处理undefined ,保证使用到的是安全可靠的 undefined。这种方式我们在日常的项目开发或者的封装也可以借鉴起来。
结束语
如果文章中什么不对或者写的不好的地方,请大家多多指正,谢谢!码字不易,点个赞加个关注吧!