异常处理

 异常是指正常情况下不会发生的所谓「例外」的情况。在大部分情况下异常和错误可以当作同义词。

异常会发生的地方

 程序的任何地方都有发生异常的可能性。
 发生异常的时候,异常将被「投出(throw)」。
 比如说,以下的脚本将会引起错误。


例:
    "3%0"!; // 发生“除以0错误”的异常


 虽然有像上例一样明显会发生异常的情况,但也有一些情况下,无法知道代码是否一定会发生异常。

异常的捕捉

 使用 try (尝试) 关键字和 catch (捕捉) 关键字,可以捕捉异常。
 例如说,为了捕捉上面所说的“不知道是否会发生的异常”,可以象下面这样编写代码。


例:
    try // 不知道是否会发生异常
    {
        func1(); // 这里有可能会发生异常
    }
    catch // 捕捉异常
    {
        // 当发生异常的时候,这里的代码被执行
        inform("无法读取图像。"); // 显示信息
    }


 像这样在 try 代码段中编写可能会发生异常的代码,就可以在发生异常的时候执行 catch 代码段中的代码。利用这个功能,可以编写出清晰流畅的错误处理代码。

 在 try 代码段中没有发生任何异常的情况下,catch 代码段不会被执行。

 try 代码段中可以编写任何的代码。除了在代码段中直接发生异常的情况之外,在代码段中调用的函数,以及被函数调用的函数中发生的异常,try ... catch 代码都可以捕捉到。

 发生异常的情况下,代码段剩下的执行步骤将被中断,并返回到 try 语句的位置。

 如果在 catch 代码段中也发生了异常,该异常便无法在这个 catch 代码段中被捕捉。这个异常将会按照调用上下文向上回溯,如果在发生错误的 catch 代码上层存在 try 语句,则异常将在那里被捕捉。

 在异常被抛出之后,程序到达 catch 块之前有发生其他异常的可能性,但这种情况下的操作未被定义。

 如果异常在脚本中完全没有被捕捉到,则异常将离开脚本而被传递给应用程序,由应用程序来进行处理。

Note
一般来说,由于错误而被抛出的异常会中断脚本的执行,所以建议尽可能在可能发生错误的地方写入 try ... catch 。

异常对象

 关于异常的各种各样的欣喜,都会和一个 Exception 类的对象一起被投出。这个对象被称做异常对象,可以通过 catch 语句来获取。
 例如说,我们可以编写以下代码。

例:
    try
    {
        loadImages("nothing.jpeg"); // 可能会发生异常的操作
    }
    catch (e) // 利用 e 这个变量获取异常对象
    {
        // e.message 是和异常一起投出的消息字符串。
        // 一些情况下发生异常的理由会通过这个变量说明。
        inform("无法读取图像。\n"+e.message);
    }

 像这样,在 catch 后的括号中写入变量名,就可以利用这个变量接收异常对象。
 这个变量的作用域,从 catch 后的代码段中开始,并随着程序离开这个代码段而结束。此外,这个变量不需要事先的声明。

throw 语句

 在 TJS 程序中可以使用 throw 关键字投出异常。
 例如,我们可以编写如下代码。

例:
    function pow2(n)
    {
        // 计算 2 的 n 次幂,提供的 n 必须是正整数
        if(n<0) throw new Exception("不能指定负数。");
            // ↑ 发生异常
        return 1<<n;
    }

 如果给这个函数传递了类似于 -1 这样的负数,就会发生异常。投出异常可以使用类似以下的语句。


throw new Exception("不能指定负数。");

 new Exception("不能指定负数。") 这个语句将以字符串作为参数创建一个新的 Exception 类对象(详细请参考 Exception 类的说明)。然后将这个新创建的对象通过 throw 关键字投出。
 throw 关键字能投出的对象并非一定要是 Exception 类的对象,数字也好,字符串也好,包括对函数的引用也能够被投出。但是,我们推荐投出 Exception 类,或者这个类的派生类的对象。这样,在 catch 代码段中只需要统一编写对应 Exception 类对象的代码即可。

再次投出异常

 catch 可以捕捉到发生的异常,但在直接对应的 try 块的上层也有可能声明了别的 try 语句。在这种情况下,可以再次投出异常。
 我们可以编写如下代码。

例:
    function tryloadimage()
    {
        try
        {
            primaryLayer.loadImages("test1.bmp"); // 尝试读取test1.bmp
        }
        catch(e)
        {
            inform("图像读取失败。");
            throw e; // 上面的信息被显示的同时,异常会被再次投出
        }
    }

    function test()
    {
        // 调用 tryloadimage ,如果读取图像成功则返回 true
        // 否则返回 false 的函数
        try
        {
            tryloadimage();
        }
        catch
        {
            return false;
        }
        return true;
    }

 在这种情况下调用 test() ,并且图像读取失败,那么在 inform 方法显示出消息的同时,由于异常被再次投出,可以通过 test 函数内的 catch 代码进行捕捉。