javascript版的quine程序
Posted tags: 篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了javascript版的quine程序相关的知识,希望对你有一定的参考价值。 引用自Wikipedia: @cowboy (Ben Alman) 给出了一个用javascript写的quine程序: 如果一个程序仅是由一个函数组成的,那么我们很容易获得这个函数的源代码:在大多数JavaScript引擎中,将一个函数转换成字符串就会返回它的源码. 我们的quine最开始是这样的: 这是一个函数声明,函数名为$(合法的JavaScript标识符).我们需要把它改写成为一个函数表达式.像这样: 等号右边是一个命名的函数表达式.函数名$只在函数内部才能访问到(译者注:作者忽略了旧版IE).调用这个函数后会发现,它已经是一个很接近quine的程序: 在调用函数之后,控制台会显示出函数的输出,以及函数的返回值undefined. 现在我们有了一个用单个函数写成的程序.但我们不想延迟它的执行,我们想让它立即执行.JavaScript允许你创建一个函数表达式的同时就立即调用这个函数.这种写法称之为立即调用函数表达式(Immmediately Invoked Function Expression)(IIFE, 发音为“iffy”,译者注:亦非). 顺便说一句,这个术语也是由Alman发明的.把我们的程序改写成IIFE之后是这样的: 一元非运算符(!)让JavaScript把这个函数解析成为一个函数表达式.否则,我们不能立即执行它 [1]. true是这个函数返回值取反后的结果:!undefined. 我们的输出还缺少一些字符:函数表达式前面的叹号!以及后面的括号.可以这样加上它们: 你还可以用小括号来括住一个IIFE: 函数表达式之前的左括号和之后的右括号在源码中都出现了两次,所以使用感叹号可以给我们省出两个字符. 一个 quine 是一个计算机程序,它不接受任何输入,且唯一的输出就是自身的源代码。 感觉挺有意思的,于是打算自己用js写一个试试。 首先确定输出方式为控制台,即通过 为有(guang)趣(gao)起见,准备从一个“打印本站域名”的“额外功能”开始: 这个命令可以在控制栏打印出一行 首先试着打印上面这个命令: 这样就在控制栏打印了一行 对了,别忘了需要执行自己,那么有: 很好,这样即执行了“额外功能”,又打印了自己的源代……不对!压根没有打印自己的源代码对吧! 很好,这次完美地打印了 不过这还远远不够!来做一点小调整: 发现了吗?这次输出了 接下来怎么办呢……来对比下上面的源码和输出的代码: 在补的时候就应该已经注意到了一个问题:转义符!这里已经无法避免转义符了!来看看输出的代码: 真好,已经十分接近了对吧!但还是有一点小问题:没错,转义符!输出时源码中的 等等……好像有什么不对?我刚才是不是把一大波 有用的反斜杠 加入源代码了?要知道,这货也是会被转义的啊!!怎么办?好嘛,来改造下反转义代码,这回单引号和反斜杠都要反转义一下: 在控制台试一试……成功!完美!强力!分毫不差地返回了自身!任务圆满完成! 怎么样,看起来很高大上的东西,其实入门很简单吧? 有人问,费劲心机写这么个东西,有啥意义?嘛,这个世界不是为了“某些人所谓的意义”而存在的。世界存在的意义在于“世界存在”这个现象本身;我折腾这个东西的意义也就在于“折腾代码”这件事本身。我觉得我获得了一些有意义的东西。你说呢? xw引: http://www.cnblogs.com/ziyunfei/archive/2012/10/05/2709428.html http://www.350351.com/plus/view.php?aid=285910&pageno=1# 以上是关于javascript版的quine程序的主要内容,如果未能解决你的问题,请参考以下文章 php PHP语言中的Quine:没有输入,一个程序打印它自己的源代码(不读取自己的源文件)一个quine是一个计算机程序,它不接受任何输入,且唯一的输出就是自身的源代码.
!function $(){console.log(\'!\'+$+\'()\')}()
获得源代码
> function foo() { return "abc" }
> String(foo)
\'function foo() { return "abc" }\'
输出自身源码的函数表达式
function $() { console.log(String($)) }
var prog = function $() { console.log(String($)) };
> prog()
function $() { console.log(String($)) }
undefined
立即调用函数表达式(IIFE)
> !function $() { console.log(String($)) }()
function $() { console.log(String($)) }
true
添加缺少的字符
> !function $() { console.log(\'!\'+$+\'()\') }()
!function $() { console.log(\'!\'+$+\'()\') }()
true
IIFE的另一种写法
(function $(){console.log(\'(\'+$+\'())\')}())
console.log
输出。console.log("perichr.org")
perichr.org
。接下来我准备一步一步改造这个命令,直至达成 quine的目标。console.log(\'console.log("perichr.org")\')
console.log("perichr.org")
。注意到源码里外用了不同的引号,这是为了规避转义符。console.log("perichr.org");console.log(\'console.log("perichr.org")\')
从简单的入手,不考虑打印完整源代码,先想想要怎样能在执行一个功能的同时打印功能代码呢?打印的是字符串,执行的是js源码……想到什么了?对了, eval
!p=\'console.log("perichr.org")\';eval(p);console.log(p)
perichr.org
和 console.log("perichr.org")
。要注意的是,这里的变量 p
没有做声明,严格模式下是通不过的哟!p=\'console.log("perichr.org");console.log(p)\';eval(p)
perichr.org
和 console.log("perichr.org");console.log(p)
!进化了!接下来先讨个巧,利用 赋值表达式返回右值 的小技巧来简化一下代码,毕竟代码越精简心理压力越小嘛……eval(p=\'console.log("perichr.org");console.log(p)\')
console.log("perichr.org");console.log(p)
,其实已经很接近了有木有!输出码就是缺少了头 eval(p=\'
和尾 \')
!来,补上!eval(p=\'console.log("perichr.org");console.log("eval(p=\\\'"+p+"\\\')")\')
eval(p=\'console.log("perichr.org");console.log("eval(p=\'"+p+"\')")\')
\\\'
被转义成了 \'
!怎么办?那就要把文本中的 \'
反转义为 \\\'
!怎么转?可以使用 "\'".replace(/\'/g,"\\\\\'")
这种方式。考虑到文本要在 p
的赋值时转义,那么就需要手动反转义为: \'.replace(/\\\'/g,"\\\\\\\\\\\'")\'
。接下来把它插入源码中:eval(p=\'console.log("perichr.org");console.log("eval(p=\\\'"+p.replace(/\\\'/g,"\\\\\\\\\\\'")+"\\\')")\')
.replace(/[\\\\\']/g,"\\\\$&")
,这里的 $&
是指返回匹配字符串。手动反转义: .replace(/[\\\\\\\\\\\']/g,"\\\\\\\\$&")
,再来一次:eval(p=\'console.log("perichr.org");console.log("eval(p=\\\'"+p.replace(/[\\\\\\\\\\\']/g,"\\\\\\\\$&")+"\\\')")\')