zoukankan      html  css  js  c++  java
  • 小tips:在JS语句执行机制涉及的一种基础类型Completion

    看一个如下的例子。在函数 foo 中,使用了一组 try 语句。在 try 中有 return 语句,finally 中的内容还会执行吗?

    function foo(){
      try{
        return 0;
      } catch(err) {
    
      } finally {
        console.log("a")
      }
    }

    得到的结果是:a 0。

    根据结果可以看出finally执行了,return语句也生效了。

    虽然 return 执行了,但是函数并没有立即返回,又执行了 finally 里面的内容,这样的行为违背了很多人的直觉。

    我们改一下上面的例子,在finally也加入return语句,如下:

    function foo(){
      try{
        return 0;
      } catch(err) {
    
      } finally {
        return 1;
      }
    }

    得到的结果是:1

    通过实际执行,我们看到,finally 中的 return “覆盖”了 try 中的 return。在一个函数中执行了两次 return,这已经超出了很多人的常识,也是其它语言中不会出现的一种行为。

    面对如此怪异的行为,我们当然可以把它作为一个孤立的知识去记忆,但是实际上,这背后有一套机制在运作。

    这一机制的基础正是 JavaScript 语句执行的完成状态,我们用一个标准类型来表示:Completion Record(Completion Record 用于描述异常、跳出等语句执行过程)。

    Completion Record 表示一个语句执行完之后的结果,它有三个字段:

    • [[type]] 表示完成的类型,有 break continue return throw 和 normal 几种类型;
    • [[value]] 表示语句的返回值,如果语句没有,则是 empty;
    • [[target]] 表示语句的目标,通常是一个 JavaScript 标签。

    JavaScript 正是依靠语句的 Completion Record 类型,方才可以在语句的复杂嵌套结构中,实现各种控制。接下来我们要来了解一下 JavaScript 使用 Completion Record 类型,控制语句执行的过程。

    语句的分类如下:

     普通语句执行后,会得到 [[type]] 为 normal 的 Completion Record,JavaScript 引擎遇到这样的 Completion Record,会继续执行下一条语句。

    这些语句中,只有表达式语句会产生 [[value]],当然,从引擎控制的角度,这个 value 并没有什么用处。

    如果你经常使用 chrome 自带的调试工具,可以知道,输入一个表达式,在控制台可以得到结果,但是在前面加上 var,就变成了 undefined。

    Chrome 控制台显示的正是语句的 Completion Record 的 [[value]]。

    现在解释下在finally也加入return语句后,为什么得到的结果为1?

    因为 finally 中的内容必须保证执行,所以 try/catch 执行完毕,即使得到的结果是非 normal 型的完成记录,也必须要执行 finally。

    而当 finally 执行也得到了非 normal 记录,则会使 finally 中的记录作为整个 try 结构的结果。

    带标签的语句的作用:与完成记录类型中的 target 相配合,用于跳出多层循环。

    实际上,任何 JavaScript 语句是可以加标签的,在语句前加冒号即可:

    firstStatement: var i = 1;

    跳出循环的例子:

    top:
      for (var i = 0; i < 3; i++){
        for (var j = 0; j < 3; j++){
          if (i === 1 && j === 1) break top;
          console.log('i=' + i + ', j=' + j);
        }
      }
    // i=0, j=0
    // i=0, j=1
    // i=0, j=2
    // i=1, j=0
  • 相关阅读:
    老调重弹--面向对象设计原则--S.O.L.I.D设计原则
    老调重弹--面向对象设计原则--GRASP设计原则
    【C#版本详情回顾】C#4.0主要功能列表
    【C#版本详情回顾】C#3.0主要功能列表
    【C#版本详情回顾】C#2.0主要功能列表
    .NET Framework和C#版本历史概览
    springmvc RESTful
    springmvc之json交互
    springmvc上传图片
    springmvc异常处理
  • 原文地址:https://www.cnblogs.com/moqiutao/p/10916381.html
Copyright © 2011-2022 走看看