Open toFrankie opened 1 year ago
众所周知,void 运算符总会返回一个 undefined 的结果。
void
undefined
那么,为什么要用 void 0 代替 undefined 呢?这不是多此一举了吗?
void 0
不急,慢慢道来~
语法非常简单:
void expression
它将会对表达式进行求值,然后返回 undefined 的「原始值」。那么,void 0 不就是得到 undefined 最简单的写法嘛!
写法上 void 0 相当于 void(0)。
void(0)
我们知道,立即函数执行表达式(IIFE)有非常多的写法,使用 void 关键字也是可以的,比如:
void (function () { // some statements })() // 相当于 void function () { /* some statements */ }()
另外,你应该看过以下类似的写法:
<a href="javascript:0;">Link</a>
我们知道 javascript: 是 JavaScript 中的伪协议,表示将会使用 JS 解析器执行其后的所有语句,若其最后一个JavaScript 语句返回值不为 undefined,那么其返回值将会替换为页面内容。
javascript:
就以上 HTML 标签,在不同浏览器下点击,会有不同的结果。其中 Chrome、Safari 中点击无任何反馈,而 Firefox 中页面内容将会被替换为 0。
0
为了解决以上差异表现,通常的做法就是使用 void 关键字,比如:
<a href="javascript:void(0);">Link</a>
这也是处理 <a> 标签默认行为的方式之一。
<a>
这种伪协议除了在事件处理程序中使用,也可在浏览器地址栏、书签地址中使用。
除此之外,还有一种常用的用法:当箭头函数中只有一行语句,且不需要返回值时,则可以:
element.onclick = () => void doSomething()
你有可能不知道,我们天天写的 undefined,它其实是一个「全局对象」中的一个「属性」。
// 浏览器宿主环境 window.undefined === undefined // true // Node 宿主环境 global.undefined === undefined // true
除了 undefined 之外,类似的还有 NaN、Infinity、globalThis 也是全局对象的属性。它们的属性描述对象都是:不可写、不可枚举、不可配置(详看 ECMAScript 19.1 Value Properties of the Global Object)。
NaN
Infinity
globalThis
{ [[writable]]: false, [[enumerable]]: false [[configurable]]: false }
当然,这个在 ES5 之前是可以被改写的,下面可以对比一下:
从这个角度看是不是可以理解为什么用 void 0 而不是 undefined 这个全局属性了。
还有,需要特别注意的是:
undefined 并不是 ECMAScript 标准中的一个保留字,因此它是可以被作为变量标识符而使用的(但项目中千万别这么用),就像 window 一样。
window
在 ECMAScript 标准中,保留字有以下这些(详见 12.6.2 Keywords and Reserved Words):
在现代浏览器下,请对比以下三种示例:
// 示例一 !(function () { var undefined = 1 console.log(undefined) // 结果是? })()
// 示例二 !(function () { undefined = 2 console.log(undefined) // 结果是? })()
// 示例三 var undefined = 3 console.log(undefined) // 结果是?
// 示例四 let undefined = 4 console.log(undefined) // 结果是?
前三个打印结果分别是:1、undefined、undefined,最后一个则在 let undefined = 4 处抛出 SyntaxError。
1
let undefined = 4
原因分析:
undefined = 2
window.undefined
non-writable
var
let/const
Uncaught SyntaxError: Identifier 'undefined' has already been declared
var undefined
let undefined
不知道有没有人会分不清:undefined 什么时候作为原始值?什么时候是作为变量(属性)?
var foo // 此处 foo 的值是原始值 undefined; function bar() {} bar() // 此处函数 bar 的返回值是原始值 undefined; void 0 // 此处 void 操作的返回值是原始值 undefined; foo == undefined // 此处相等运算符右侧的 undefined 是全局对象的 undefined 属性。
到这里,你应该对于 undefined 有了一个比较全面的认识了。
我猜你应该看过类似以下的「小心机」代码:
;(function ($, window, undefined) { // some statements })(jQuery, window)
如果在 IIFE 中使用 undefined,它其实是引用了形参 undefined。但形参 undefined 的值就是 undefined 的原始值,因为在调用函数时并未传入实参。除了能确保 undefined 的值是原始值之外,还能加速变量 undefined 的查找,由于它在函数作用域内就能找到该变量,就不会继续往作用域链上查找。
void 0 总是返回原始值 undefined,无论全局属性 undefined 是否被改写,它都能确保其值是 undefined(原始值)。
比如著名的工具库 underscore 大量使用了 void 0 来代替 undefined,再者 UglifyJS、Terser 等代码压缩工具也会将 undefined 转换为 void 0,这样可以节省一些字节:
function isUndefined(x) { return x === undefined } // Minified function isUndefined(n){return void 0===n}
但我们在编写代码的时候,直接使用 undefined 也是没有太大问题的,注意下前面提到的一些点就好了,其余的就交由工具来处理即可。
众所周知,
void
运算符总会返回一个undefined
的结果。那么,为什么要用
void 0
代替undefined
呢?这不是多此一举了吗?不急,慢慢道来~
void 运算符
语法非常简单:
它将会对表达式进行求值,然后返回
undefined
的「原始值」。那么,void 0
不就是得到undefined
最简单的写法嘛!我们知道,立即函数执行表达式(IIFE)有非常多的写法,使用
void
关键字也是可以的,比如:另外,你应该看过以下类似的写法:
我们知道
javascript:
是 JavaScript 中的伪协议,表示将会使用 JS 解析器执行其后的所有语句,若其最后一个JavaScript 语句返回值不为undefined
,那么其返回值将会替换为页面内容。就以上 HTML 标签,在不同浏览器下点击,会有不同的结果。其中 Chrome、Safari 中点击无任何反馈,而 Firefox 中页面内容将会被替换为
0
。为了解决以上差异表现,通常的做法就是使用
void
关键字,比如:这也是处理
<a>
标签默认行为的方式之一。这种伪协议除了在事件处理程序中使用,也可在浏览器地址栏、书签地址中使用。
除此之外,还有一种常用的用法:当箭头函数中只有一行语句,且不需要返回值时,则可以:
undefined
你有可能不知道,我们天天写的
undefined
,它其实是一个「全局对象」中的一个「属性」。当然,这个在 ES5 之前是可以被改写的,下面可以对比一下:
从这个角度看是不是可以理解为什么用
void 0
而不是undefined
这个全局属性了。还有,需要特别注意的是:
在 ECMAScript 标准中,保留字有以下这些(详见 12.6.2 Keywords and Reserved Words):
在现代浏览器下,请对比以下三种示例:
前三个打印结果分别是:
1
、undefined
、undefined
,最后一个则在let undefined = 4
处抛出 SyntaxError。原因分析:
undefined
被声明为一个变量标识符,并赋值为1
,因此打印结果为1
;undefined = 2
表示修改全局变量的undefined
属性(window.undefined
),由于它是non-writable
的,因此不会被重写,打印结果还是其默认值undefined
;var
和let/const
的区别,在全局作用域下,前者声明的变量会被添加至全局对象上,而后者则不会。但是实际执行下来,会抛出语法:Uncaught SyntaxError: Identifier 'undefined' has already been declared
(目测是默认情况下就有一个var undefined
的声明的语句了,因此使用let undefined
重复声明会抛出错误,这种猜测暂未在标准中找到佐证)。不知道有没有人会分不清:
undefined
什么时候作为原始值?什么时候是作为变量(属性)?到这里,你应该对于
undefined
有了一个比较全面的认识了。我猜你应该看过类似以下的「小心机」代码:
如果在 IIFE 中使用
undefined
,它其实是引用了形参undefined
。但形参undefined
的值就是undefined
的原始值,因为在调用函数时并未传入实参。除了能确保undefined
的值是原始值之外,还能加速变量undefined
的查找,由于它在函数作用域内就能找到该变量,就不会继续往作用域链上查找。用 void 0 代替 undefined?
void 0
总是返回原始值undefined
,无论全局属性undefined
是否被改写,它都能确保其值是undefined
(原始值)。比如著名的工具库 underscore 大量使用了
void 0
来代替undefined
,再者 UglifyJS、Terser 等代码压缩工具也会将undefined
转换为void 0
,这样可以节省一些字节:但我们在编写代码的时候,直接使用
undefined
也是没有太大问题的,注意下前面提到的一些点就好了,其余的就交由工具来处理即可。