介绍
如何写一段javascript程序,输出自身的源代码?这个问题非常有意思,大家不妨先尝试一下,反正在尝试了半个小时之后,我果断放弃了。
这种能输出自身的程序在英文里被称为quine
。
准备知识
其实要实现这样一段程序,至少要掌握javascript中两个重要的知识点:
- IIFE
- toString()方法
关于toString()
方法,相信大家也不陌生,但是你可知道对于一个函数来说,调用toString()
方法意味着什么?
没错,调用一个函数的toString()
方法会返回这个函数的源代码。
function foo() {
console.log('hello world')
}
console.log(foo.toString()) // 输出foo的源代码
第一个例子
有了上面的知识储备,我们可以动手写一下了,首先写一个函数foo
,在函数体内调用console.log(foo.toString())
输出函数的源代码。
function foo() {
console.log(foo.toString())
}
但是这只是函数定义,并未执行,所以需要在函数定义之后调用它。
function foo() {
console.log(foo.toString())
}
foo() // 调用函数,输出源代码
运行上面的代码,输出的结果如下所示,可以看到最后的调用语句foo()
并没有打印出来。
function foo() {
console.log(foo.toString())
}
这不符合我们的要求,所以考虑去掉调用语句,将函数改为IIFE的形式
(function foo() {
console.log(foo.toString())
})()
运行上面的代码,输出的结果如下,最外层的()
和末尾调用函数的()
没有打印出来,这也不符合我们的要求。
function foo() {
console.log(foo.toString())
}
改造一下内部的console.log
,将两组括弧也输出来。
(function foo() {
console.log('(' + foo.toString() + ')()')
})()
这回结果终于正确了,我们进一步改造,使用+
拼接字符串时,js会自动将+
另一侧的操作数转换为字符串,所以我们可以把toString()
省略掉。
(function foo() {
console.log('(' + foo + ')()')
})()
再增加点神秘感,将foo换成$
(function $() {
console.log('(' + $ + ')()')
})()
运行结果如下:
(function $() {
console.log('(' + $ + ')()')
})()
这就是一个简单的javascript quine了。
最短的例子
在上面的例子中,为了便于观察结果,使用了console.log
输出了源代码,实际上我们可以直接返回源代码,这样就可以省略掉console.log
语句。
(function $() {
return '(' + $ + ')()'
})()
根据前面两篇文章学到的IIFE
的知识,我们使用IIFE的箭头函数形式。下面这段代码定义一个箭头函数并将其赋值给变量$
,然后立即执行这个函数。
($ = () => {
return '(' + $ + ')()'
})()
但是它的执行结果中没有包含$
,我们加上$
($ = () => {
return '($ =' + $ + ')()'
})()
根据箭头函数的规则,如果返回值只有一行,那么可以省略掉大括号{}
和return
关键字,所以我们可以进一步简化为
($ = () => '($ =' + $ + ')()')()
再将字符串拼接操作改为ES6的模板字符串形式:
($ = () => `($ = ${$})()`)()
最后去掉空格,得到如下代码。
($=()=>`($=${$})()`)()
这就是史上最短的javascript quine
了。需要注意的是,上面的代码需要在浏览器的控制台中运行,如果在IDE中运行,代码格式化工具可能会将代码格式化,导致结果不正确。
你还能想到其他办法吗?欢迎在评论区分享你的想法。
文章转载自: 前端风云志