无聊的时候想到用jscript模拟Console程序,结果试了一下,觉得还蛮好玩的:P 实现了一个jscript“控制台”类 在读代码前先放出三个Demo: http://akira.bigwww.com/Silver%20Luna/Demos/ConsoleDemo.html 通过“控制台”输入两个数求和
http://akira.bigwww.com/Silver%20Luna/Demos/ConsoleDemo2.html 通过“控制台”输入一个句子,统计字符类型和数量
http://akira.bigwww.com/Silver%20Luna/Demos/ConsoleDemo3.html 一个可以通过键盘敲入命令回车执行的模拟,还支持 begin Codes... end 的模式 :) 下面是程序代码: //控制台类,模拟运行在控制台上的程序,可以控制“标准输入输出流”(程序模拟) //使用方法:在页面上包含Console.js文件,构造Console对象,定义Main()函数,在Main函数中写控制命令 //版本:1.00 //作者:Akira //编写日期:2004-11-19 function Console(page, consoleName) { //静态成员 Console.KEY_ENTER = 13; //回车键 Console.KEY_RETURN = 13; //回车 Console.KEY_NEWLINE = 10; //换行 Console.KEY_TAB = 9; //TAB键 Console.KEY_BACKSPACE = 8; //退格键 Console.KEY_LEFT = 37; //左移 Console.KEY_RIGHT = 38; //右移 Console.KEY_UP = 39; //上移 Console.KEY_DOWN = 40; //下移 //初始化Page if (page == null) { page = self; } if (page != self) { //do sth here... throw new Error("参数错误:目前版本不支持为其他窗体对象初始化控制台\n请使用self参数"); } this.page = page; //输入输出流属性,用字符串数组模拟流 this.stream = new Object(); this.stream.stdin = new Array(); //标准输入流 this.stream.stdout = new Array(); //标准输出流 this.stream.stderr = new Array(); //标准错误流 this.stream.stdin.opened = false; //判断当前输入流是否开启,开启=允许写入 this.stream.stdin.ReadOffset = 0; //判断当前输入流偏置,Read()方法使用 this.stream.semaphores = 0; //流信号量,用来控制输出流显示,当调用输入函数时,信号量增加, //当信号量大于stdin成员数目的时候,抛出异常阻塞标准输出流,用以模拟输入等待 Console.prototype.Signal = function() { if(this.stream.semaphores == this.stream.stdin.length) { return true; } if(this.stream.semaphores > this.stream.stdin.length) { throw new WaitForInput(); //抛出异常阻止程序往下执行,用以等待输入 } return false; } this.body = page.document.body; if (this.body == null) { throw new Error("控制台缺初始化失败,检查主体文档是否缺少BODY标记"); } this.page.document.title += "——Javascript控制台"; this.page.PageLoadEventSender = this; this.body.onload = function(){this.PageLoadEventSender.PageLoad(this.PageLoadEventSender,this.PageLoadEventSender.page.event);} //定义PageLoad事件 this.page.ResizeEventSender = this; this.body.onresize = function(){this.ResizeEventSender.OnResize(this.ResizeEventSender,this.ResizeEventSender.page.event);} this.ConsoleMain = page.document.getElementById(consoleName); //可以通过参数指定初始化对象TEXTAREA的名称,这样可以把控制台 //主窗口嵌入在网页中 //如果没有指定获得TEXTAREA对象,则建立控制台主窗口,并让窗口占据整个页面 if (this.ConsoleMain == null) { this.body.style.background = "#000000"; this.page.document.bgColor = "#000000"; this.ConsoleMain = page.document.createElement("textarea"); page.document.body.appendChild(this.ConsoleMain); this.ConsoleMain.style.width="100%"; this.ConsoleMain.style.height="100%"; this.ConsoleMain.style.overflowX="hidden"; this.ConsoleMain.style.overflowY="hidden"; this.ConsoleMain.style.border="0px"; this.ConsoleMain.style.background="#000000"; this.ConsoleMain.style.color="C0C0C0"; } if (this.ConsoleMain.tagName.toUpperCase() != "TEXTAREA") { throw new Error("控制台主窗口类型错误,主窗口对象必须为TEXTAREA类型"); } this.ConsoleMain.KeyPressSender = this; //KeyPress事件 this.ConsoleMain.onkeypress = function(){this.KeyPressSender.ConsoleMain_KeyPress(this.KeyPressSender, this.KeyPressSender.page.event);} this.ConsoleMain.KeyUpSender = this; //KeyUp事件 this.ConsoleMain.onkeyup = function(){this.KeyUpSender.ConsoleMain_KeyUp(this.KeyUpSender, this.KeyUpSender.page.event);} this.ConsoleMain.KeyDownSender = this; //KeyDown事件 this.ConsoleMain.onkeydown = function(){return(this.KeyDownSender.ConsoleMain_KeyDown(this.KeyDownSender, this.KeyDownSender.page.event));} this.ConsoleMain.ClickSender = this; //Click事件,用来避免光标位置随鼠标点击而改变 this.ConsoleMain.onclick = function(){this.ClickSender.ConsoleMain_Click(this.ClickSender, this.ClickSender.page.event);} //Event Handlers Console.prototype.PageLoad = function(sender, event) //PageLoad事件处理,调用this.Main()方法用来初始化控制台 { //create frameConsole this.Main(); } Console.prototype.OnResize = function(sender, event) //Resize事件处理,将文字正确显示在控制台顶部 { this.SetCursor(); } Console.prototype.ConsoleMain_KeyDown = function(sender, event) { if (event.keyCode == Console.KEY_TAB) //处理TAB键,避免主窗口失去焦点 { this.ConsoleMain.value += "\t"; if (!this.stream.stdin.opened) { this.stream.stdin.push("\t"); this.stream.stdin.opened = true; } else { this.stream.stdin[this.stream.stdin.length - 1] += "\t"; } return false; } if (event.keyCode == Console.KEY_LEFT ||event.keyCode == Console.KEY_RIGHT ||event.keyCode == Console.KEY_UP ||event.keyCode == Console.KEY_DOWN) //忽略方向键,锁定光标 { return false; } return true; } Console.prototype.ConsoleMain_KeyUp = function(sender, event) { if (event.keyCode == Console.KEY_ENTER) //处理回车键结束流的写入 { if(!this.stream.stdin.opened) //忽略空行和连续回车 return; else { this.stream.stdin.opened = false; this.Main(); //结束流的写入,并让程序继续往下执行 } } if (event.keyCode == Console.KEY_BACKSPACE) //处理退格键 { if (!this.stream.stdin.opened) //忽略当前流为空时的退格键 { return; } else { if (this.stream.stdin[this.stream.stdin.length - 1].length == 0) { return; } this.stream.stdin[this.stream.stdin.length - 1] = this.stream.stdin[this.stream.stdin.length - 1].substr(0, this.stream.stdin[this.stream.stdin.length - 1].length - 1); if (this.stream.stdin[this.stream.stdin.length - 1].length == 0) { this.stream.stdin.length--; this.stream.stdin.opened = false; } } } } Console.prototype.ConsoleMain_KeyPress = function(sender, event) //键盘事件,将字符写入流 { if (!this.stream.stdin.opened) //New Stream { if (event.keyCode != Console.KEY_ENTER) { this.stream.stdin.push(String.fromCharCode(event.keyCode)); this.stream.stdin.opened = true; } } else { if (event.keyCode != Console.KEY_ENTER) this.stream.stdin[this.stream.stdin.length - 1] += String.fromCharCode(event.keyCode); } } Console.prototype.ConsoleMain_Click = function(sender, event) { this.SetCursor(); } //Methods Console.prototype.init = function() //初始化方法,在this.Main()中被调用 { //this.ConsoleMain.value="控制台初始化完成...\n"; this.ConsoleMain.contentEditable = true; this.stream.semaphores = 0; this.stream.stdin.ReadOffset = 0; this.stream.stdin.opened = false; } Console.prototype.WriteLine = function(msg) //写入一行文本到标准输出流 { if (this.Signal()) { this.ConsoleMain.value+=msg+"\n"; this.stream.stdout.push(msg+"\n"); } } Console.prototype.Write = function(msg) //写入一个字符串到标准输出流 { if (this.Signal()) { this.ConsoleMain.value+=msg; this.stream.stdout.push(msg); } } Console.prototype.Error = function(msg) //写入错误信息到标准错误流 { if (this.Signal()) { this.ConsoleMain.value+=msg; this.stream.stderr.push(msg); } } Console.prototype.ReadLine = function() //从标准输入流读取一行 { if (this.Signal()) { this.SetCursor(); //光标移至输入位置 throw new WaitForInput(); //抛出异常阻止程序往下执行,用以等待输入 } this.stream.semaphores++; if (this.stream.semaphores <= this.stream.stdin.length) { if (isNaN(this.stream.stdin[this.stream.semaphores - 1])) //非数字返回对象 { return this.stream.stdin[this.stream.semaphores - 1]; } else { return this.stream.stdin[this.stream.semaphores - 1] - 0; //数字返回数值 } } } Console.prototype.SetCursor = function() { this.ConsoleMain.focus(); var range = this.ConsoleMain.createTextRange(); range.moveStart('character',this.ConsoleMain.value.lenght); range.collapse(false); range.select(); } Console.prototype.Read = function() //从标准输入流读取下一个字符 { if (this.Signal() && this.stream.stdin.ReadOffset == 0) { this.ConsoleMain.focus(); var range = this.ConsoleMain.createTextRange(); range.moveStart('character',this.ConsoleMain.value.lenght); range.collapse(false); range.select(); this.stream.stdin.push(""); this.stream.stdin.opened=true; throw new WaitForInput(); //抛出异常阻止程序往下执行,用以等待输入 } else if (this.stream.semaphores <= this.stream.stdin.length) { if (this.stream.stdin.ReadOffset == 0) //读取流的第一个字符,信号量增加 { this.stream.semaphores++; } if (this.stream.stdin.ReadOffset < this.stream.stdin[this.stream.semaphores - 1].length) { return this.stream.stdin[this.stream.semaphores - 1].charCodeAt(this.stream.stdin.ReadOffset++); } else if(this.stream.stdin.ReadOffset == this.stream.stdin[this.stream.semaphores - 1].length) //恢复在流的末尾被忽略的回车和换行 { this.stream.stdin.ReadOffset++; return Console.KEY_RETURN; } else if(this.stream.stdin.ReadOffset == this.stream.stdin[this.stream.semaphores - 1].length + 1) { this.stream.stdin.ReadOffset=0; return Console.KEY_NEWLINE; } else { throw new Error("Stack over flow! Read Error!"); } } } Console.prototype.Main = function() { this.init(); try { Main(); if (this.Signal()) { this.Dispose(); } } catch(e) { if (e instanceof WaitForInput) { } else { this.Error("错误:" + e.number + "," + e.name + ":" + e.message); //将错误信息写入标准错误流 this.Dispose(); } } } Console.prototype.Dispose = function() //结束控制台流程,按任意键关闭窗口 { this.ConsoleMain.contentEditable = false; this.ConsoleMain.focus(); this.Write("\nPress any key to continue...\n"); this.ConsoleMain.KeyDownSender = this; this.ConsoleMain.onkeydown = function(){this.KeyDownSender.page.close();return false;} } } //等待输入的“异常”类,用来在要求用户输入的时候阻塞程序的运行。 function WaitForInput() { }WaitForInput.prototype = new Error(); //调试控制台——可运行和调试javascript程序段 //版本:0.01 Demo //作者:Akira //日期:2004-11-19 function DebugConsole() { DebugConsole.prototype.RunCommand = function(command) { if (this.Signal()) { var regexp = new RegExp("document.writeln","g"); command = command.replace(regexp, "this.WriteLine"); regexp = new RegExp("document.write","g"); command = command.replace(regexp, "this.Write"); try { eval(command); } catch(e) { this.Error("指令无效:" + e.number + "," + e.name + ":" + e.message + "\n"); } } } DebugConsole.prototype.Start = function() { this.WriteLine("调试控制台初始化...完成!"); var command = ""; var process = ""; var runProc = false; while ((command = this.ReadLine()) != "stop") { if (command == "begin") { process=""; runProc = true; //执行一组命令 continue; } if (command == "end") { this.RunCommand(process); runProc = false; continue; } if (command.charAt(0) == "=") { command = "this.WriteLine(" + command.substring(1) + ");"; } if (!runProc) { this.RunCommand(command); //执行一条命令 } else { process += command; } } } }DebugConsole.prototype = new Console(); //这个控制台目前的缺点是:1)异常信息无法显示行号 2)不能在新开窗口中动态建立控制台 //有待改进......

|