JavaScriptjavascript调试原理(二)中给出一个模拟客户端调试的例子,在客户端有两个问题:
1.如何获得当前的context?
2.如何做resume,stepinto,stepreturn,stepover?
本章围绕着这两个问题展开讨论
1.如何获得当前的context
我们先看一段代码:
- function test(){
- this.a = "a";
- var b = "b";
- }
那么在进入test之后,如何获得a和b的值呢?
a的值比较简单,只要把this传过去,通过for...in语句就可以获得,但是b呢?它相当于一个私有变量,在外面是不能访问的,要访问b只能通过在b所在的作用域中获得,因此我们在插入前面的每一行中要加上一个eval函数,eval函数的作用域是当前行的,所以可以获得当前行的上下文。所以在第二章中才会在每一行加上
- function(text){try{return eval(text)}catch(e){}});
我们把a,b,c加上看一下效果
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
- <HTML>
- <HEAD>
- <TITLE> New Document </TITLE>
- <META NAME="Generator" CONTENT="EditPlus">
- <META NAME="Author" CONTENT="">
- <META NAME="Keywords" CONTENT="">
- <META NAME="Description" CONTENT="">
- </HEAD>
- <BODY>
- <textarea id="jsstr" readonly style="400px;height:200px">function test(){
- var a = test1();
- var b = test2();
- var c = "result is " + a + b;
- alert(c);
- }
- function test1(){
- return "test1-->abc";
- }
- function test2(){
- return "test2-->abc";
- }
- test();</textarea>
- <div id="result">
- </div>
- <script>
- var debugStr = "";
- function jsdebug(resource,line,evalFunc){
- var lines = debugStr.split("\n");
- var jsLine = lines[line-1];
- lines[line-1] = "当前行:--->" + jsLine;
- var arr = [
- "调试代码:",
- lines.join("\n"),
- "==========context===========",
- "a = " + evalFunc("a"),
- "b = " + evalFunc("b"),
- "c = " + evalFunc("c"),
- ];
- var result = document.getElementById("result");
- result.innerHTML = result.innerHTML + "<br>执行到第" + line + "行: -->" + jsLine;
- alert(arr.join("\n"));
- }
- function debug(str){
- var lines = str.split("\n");
- debugStr = str;
- var codes = [];
- for(var i=0;i<lines.length;i++){
- codes[i] = "jsdebug('test'," + (i+1) + ",function(text){try{return eval(text)}catch(e){}});" + lines[i];
- }
- eval(codes.join('\n'));
- }
- debug(document.getElementById('jsstr').value);
- </script>
- </BODY>
- </HTML>
在执行到第3,4,5行的时候可以看到a,b,c的值
这里又有一个问题:我怎么知道函数中有哪些变量?
这就要用到arguments.callee.caller了,把函数当成一个字条串解析,解析出函数的输入参数及定义的变量,就能拿到一个变量名的集合,然后再一个一个地取值。具体的算法这里就不给出了。
再说第二个问题,如何控制stepinto,stepreturn,resume
我们需要在客户端维护一个函数的调用栈,这个栈中记录着每一步的调用,在执行的时候根据栈中存的信息和当前的上下文比较,就能拿到当前语句究竟是stepover还是stepinto还是stepreturn。
那么如何做resume呢,客户端维护一份断点列表,执行每一句的时候判断是否到了断点,不在断点就继续执行,到了断点就停止。
这部分内容也不再给出详细代码,请参照Javascript Debug Toolkit的源代码