如果我自己抛出一个JavaScript异常(例如,抛出“AArrggg”),我如何获得堆栈跟踪(在Firebug或其他)?现在我刚收到消息。

编辑:正如下面许多人发布的那样,可以为JavaScript异常获得堆栈跟踪,但我想为我的异常获得堆栈跟踪。例如:

function foo() {
    bar(2);
}
function bar(n) {
    if (n < 2)
        throw "Oh no! 'n' is too small!"
    bar(n-1);
}

当调用foo时,我想获得一个堆栈跟踪,其中包括对foo, bar, bar的调用。


当前回答

Chrome/Chromium和其他使用V8的浏览器,以及Firefox,都有一个方便的接口来通过Error对象的stack属性获取堆栈跟踪:

    try {
        // Code throwing an exception
        throw new Error();
    } catch(e) {
        console.log(e.stack);
    }

详见V8文档

其他回答

<script type="text/javascript"
src="https://rawgithub.com/stacktracejs/stacktrace.js/master/stacktrace.js"></script>
<script type="text/javascript">
    try {
        // error producing code
    } catch(e) {
        var trace = printStackTrace({e: e});
        alert('Error!\n' + 'Message: ' + e.message + '\nStack trace:\n' + trace.join('\n'));
        // do something else with error
    }
</script>

这个脚本将显示错误

对Eugene的回答进行了更新:为了让IE(特定版本?)填充堆栈属性,必须抛出错误对象。下面的例子应该比他现在的例子工作得更好,并且应该避免在IE中返回undefined。

function stackTrace() {
  try {
    var err = new Error();
    throw err;
  } catch (err) {
    return err.stack;
  }
}

注1:这类事情只应该在调试时执行,在运行时禁用,特别是频繁调用时。注2:这可能不能在所有浏览器中工作,但似乎可以在FF和IE 11中工作,这很适合我的需求。

有点晚了,但是,这里有另一个解决方案,它自动检测if参数。callee可用,并使用new Error()。如果没有,就堆叠。 在chrome, safari和firefox测试。

2个变体——stackFN(n)给出了离直接调用方n远的函数名,stackArray()给出了一个数组,stackArray()[0]是直接调用方。

在http://jsfiddle.net/qcP9y/6/上试试吧

// returns the name of the function at caller-N
// stackFN()  = the immediate caller to stackFN
// stackFN(0) = the immediate caller to stackFN
// stackFN(1) = the caller to stackFN's caller
// stackFN(2) = and so on
// eg console.log(stackFN(),JSON.stringify(arguments),"called by",stackFN(1),"returns",retval);
function stackFN(n) {
    var r = n ? n : 0, f = arguments.callee,avail=typeof f === "function",
        s2,s = avail ? false : new Error().stack;
    if (s) {
        var tl=function(x) { s = s.substr(s.indexOf(x) + x.length);},
        tr = function (x) {s = s.substr(0, s.indexOf(x) - x.length);};
        while (r-- >= 0) {
            tl(")");
        }
        tl(" at ");
        tr("(");
        return s;
    } else {
        if (!avail) return null;
        s = "f = arguments.callee"
        while (r>=0) {
            s+=".caller";
            r--;   
        }
        eval(s);
        return f.toString().split("(")[0].trim().split(" ")[1];
    }
}
// same as stackFN() but returns an array so you can work iterate or whatever.
function stackArray() {
    var res=[],f = arguments.callee,avail=typeof f === "function",
        s2,s = avail ? false : new Error().stack;
    if (s) {
        var tl=function(x) { s = s.substr(s.indexOf(x) + x.length);},
        tr = function (x) {s = s.substr(0, s.indexOf(x) - x.length);};
        while (s.indexOf(")")>=0) {
            tl(")");
            s2= ""+s;
            tl(" at ");
            tr("(");
            res.push(s);
            s=""+s2;
        }
    } else {
        if (!avail) return null;
        s = "f = arguments.callee.caller"
        eval(s);
        while (f) {
            res.push(f.toString().split("(")[0].trim().split(" ")[1]);
            s+=".caller";
            eval(s);
        }
    }
    return res;
}


function apple_makes_stuff() {
    var retval = "iPhones";
    var stk = stackArray();

    console.log("function ",stk[0]+"() was called by",stk[1]+"()");
    console.log(stk);
    console.log(stackFN(),JSON.stringify(arguments),"called by",stackFN(1),"returns",retval);
    return retval;
}



function apple_makes (){
    return apple_makes_stuff("really nice stuff");
}

function apple () {
    return apple_makes();
}

   apple();

在Firefox中,似乎不需要抛出异常。这就足够了

e = new Error();
console.log(e.stack);
function stacktrace(){
  return (new Error()).stack.split('\n').reverse().slice(0,-2).reverse().join('\n');
}