JavaScript Quine揭秘:如何让程序输出自身源代码?

11 阅读2分钟

介绍

如何写一段javascript程序,输出自身的源代码?这个问题非常有意思,大家不妨先尝试一下,反正在尝试了半个小时之后,我果断放弃了。

这种能输出自身的程序在英文里被称为quine

准备知识

其实要实现这样一段程序,至少要掌握javascript中两个重要的知识点:

  1. IIFE
  2. 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中运行,代码格式化工具可能会将代码格式化,导致结果不正确。

你还能想到其他办法吗?欢迎在评论区分享你的想法。

文章转载自: 前端风云志

原文链接: www.cnblogs.com/graphics/p/…

体验地址: www.jnpfsoft.com/?from=001YH