一. Completion Record(完成记录)

表达式返回的值在内部叫Completion Record,是一个内部对象,它有如下属性

描述
[[type]] normal, break, continue,
retur, throw
完成的类型,用于描述控制流
[[value]] 字符串或空(empty) 产生的值
[[target]] 字符串或空(empty) 控制流的转移目标,类似于goto
break,continue加标签可以转移到指定层

二. BlockStatement(语句块)

语句块,可以形成一个新的词法环境
Completion Record如下
[[type]]:normal

  1. {
  2. ...
  3. }

三. Iteration

  1. 循环的类型Completion Record可以是break或continue,加标签可以转移到指定层;
  2. 只有循环/swicth识别并消费标签语句
    • LabelledStatement
    • IterationStatement
    • continueStatement
    • BreakStatement
    • SwitchStatement

[[type]]: break, continue
[[target]]: label

  1. 以下是循环的语法
    1. while
    2. do while
    3. for
    4. for in
    5. for of
    6. for await of

    1. for

    for声明可以独立的产生作用域,范围在for语句的block之外;这里i只声明了一次 ```javascript /* 这里打印10个0,每次循环使用的外面的i / for(let i = 0; i < 10; i++) { let i = 0 console.log(i); }

/ 理解,类似于如下的代码 */ { / 这是for产生的作用域 / let i = 1; console.log(i); { /** 这里是for{}内的环境 / let i = 0; console.log(i); } }

  1. <a name="nIVzA"></a>
  2. ### 2. for of
  3. 1. 可以循环数组的值
  4. 1. 任何能有迭代的对象都可以循环,如可以循环generator函数
  5. 示例如下
  6. ```javascript
  7. function *p() {
  8. yield 0;
  9. yield 1;
  10. yield 2;
  11. }
  12. for(let i of p()) {
  13. console.log('i :>> ', i);// 0 1 2
  14. }

3. for in

由于in会产生冲突,所以for in 中不能使用in语法

4. Label语法

类似于goto,可以解决break双层循环的问题,性能没有问题。

四. try catch

try…catch语法的Completion Record如下
[[type]]:return
[[target]]:label

  1. try {
  2. throw 2;
  3. } catch(e) {
  4. let e;
  5. console.log(e);
  6. }

五. 声明

  • FunctionalDeclaration 函数声明
  • GeneratorDeclaration Generator声明
  • AsyncFunctionDeclaration 异步
  • AsyncGeneratorDeclaration 异步Generator
  • VariableStatement 变量声明
  • ClassDeclaration class声明
  • LexicalDeclaration

    1. 异步Generator

    可以for await of调用 ```javascript /* 一秒输出一个自增的数 / function sleep(d) { return new Promise((resolve) => setTimeout(resolve, d)); }

async function *p() { let i = 0; while(true) { await sleep(1000); yield ++i; } }

for await (let i of p()) { console.log(‘i :>> ‘, i); }

  1. <a name="cXH0U"></a>
  2. ### 2. 变量声明
  3. 1. var声明的范围:**函数**;
  4. 在编译阶段,所有的var声明和函数声明会被放在词法环境中Lexical Environment,var 变量初始化一个`undefined`值。function声明同理,初始化成一个函数。<br />为什么var声明的范围会在函数部分:<br />因为词法环境是执行上下文的一部分(可以把执行上下文看成是一个对象,词法环境是一个属性),js引擎每调用一个函数便创建执行上下文并压入执行上下文栈中。<br />参考:[详解ES6执行时词法环境/作用域/执行上下文/执行栈和闭包](https://juejin.cn/post/6926831181681917959)<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/23168078/1646669581876-b4147780-0693-48f0-9f83-7ca1d2ee6741.png#clientId=u4a17f202-7d28-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=334&id=u26337fb1&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1000&originWidth=1466&originalType=binary&ratio=1&rotation=0&showTitle=false&size=115991&status=done&style=none&taskId=u3c6e292e-ccce-4da2-b22f-5efd6e0edbd&title=&width=490.36358642578125)
  5. ```javascript
  6. console.log(name); // undefined
  7. var name = 'a';
  8. console.log(name); // a
  9. /** js引擎内部,编译阶段 */
  10. lexicalEnvironment = {
  11. name: undefined
  12. }
  13. /** js引擎内部,执行阶段 */
  14. lexicalEnvironment = {
  15. name: 'a'
  16. }
  1. 所以function内部第一次使用变量的时候声明

    3. class声明

    声明之前不能使用,否则会报错