zoukankan      html  css  js  c++  java
  • JavaScript 预编译与作用域

    预编译

    JavaScript 执行步骤

    检查通篇的语法错误 -> 预编译 -> 解释执行

    暗示全局变量

    变量不声明直接赋值,挂载到 window 对象下

    a = 1;
    console.log(a); // 1
    
    function test() {
        var b = c = 1;
    }
    test();
    console.log(c); // 打印 1,c 未声明,直接赋值,暗示全局变量
    console.log(window.b); // undefined,打印对象不存在属性,返回 undefined
    console.log(b); // 报错

    预编译过程

    函数声明整体提升

    变量声明提升,赋值不提升

    test(); // 放在前面可以执行
    function test() {
    
    }
    console.log(a); // 打印出 undefined
    var a = 1; // 声明提升,赋值不提升
     

    GO

    global object,全局上下文,即 window 对象

    在全局执行的前一刻,生成 GO,即变量声明提升和函数声明提升

    步骤:寻找变量声明 -> 寻找函数声明 -> 顺序执行

    var a = 1; // (1)
    function a() {
        console.log(2);
    }
    console.log(a); // (2)
    // 全局预编译
    // 变量声明 a -> GO{a: undefined} 
    // 函数声明 a(){} -> GO{a: a(){}} 
    // 全局执行
    // 执行 (1) -> GO{a: 1}
    // 执行 (2),打印 1
    console.log(a); // (1)
    var a = 1; // (2)
    console.log(a); // (3)
    function a() {
       console.log(2);
    }
    // 全局预编译
    // 变量声明 a -> GO{a: undefined} 
    // 函数声明 a(){} -> GO{a: a(){}}
    // 全局执行
    // 执行 (1),打印 a(){...}
    // 执行 (2) -> GO{a: 1}
    // 执行 (3),打印 1
     

    AO

    activation object,函数上下文,即活跃对象

    每个函数都有自己的 AO,函数执行前一刻生成,执行完以后销毁

    步骤:寻找形参和变量声明 -> 形参实参映射 ->寻找函数声明 -> 顺序执行

    注意:AO 中有 var a 声明,不会找 GO 里的 a

    function test(a) {
        console.log(a); // (1)
        var a = 1; // (2)
        console.log(a); // (3)
        function a() {}
        console.log(a); // (4)
        var b = function() {} // (5)
        console.log(b); // (6)
        function d() {}
    }
    test(2); 
    // 全局预编译
    // 函数声明 test(){} -> GO{a: test(){}} 
    // 全局执行
    // 执行到 test(2),函数 test 预编译
    // 变量声明 a, b -> test_AO{a: undefined, b: undefined}
    // 参数映射 -> test_AO{a: 2, b: undefined}
    // 函数声明 -> test_AO{a: a(){}, b:undefined, d: d(){}}
    // 函数 test 执行
    // 执行 (1),打印 a(){}
    // 执行 (2) -> test_AO{a: 1, b: undefined, d: d(){}}
    // 执行 (3),打印 1
    // 执行 (4),打印 1
    // 执行 (5) -> test_AO{a: 1, b: (){}, d: d(){}}
    // 执行 (6),打印 (){}
    // 函数 test 执行完毕,test_AO 销毁

    练习

    a = 1; // (1)
    function test() {
        console.log(a); // (2)
        a = 2; // (3)
        console.log(a); // (4)
        if(a) { // (5),预编译时不看 if,因为没有执行该句
            var a = 3; 
        }
        console.log(a); // (6)
    }
    test();
    var a;
    // 全局预编译
    // 变量声明、函数声明 -> GO{a: undefined, test: test(){}}
    // 全局执行
    // 执行 (1) -> GO{a: 1, test: test(){}}
    // 执行到 test(),函数 test 预编译
    // 变量声明 -> test_AO{a: undefined}
    // 函数 test 执行
    // 执行 (2),打印 undefined
    // 执行 (3) -> AO{a: 2}
    // 执行 (4),打印 2
    // 执行 (5) -> AO{a: 3}
    // 执行 (6) -> 打印 3
    // 函数 test 执行完毕,test_AO 销毁
     

    作用域

    函数的属性

    函数是一种引用类型

    有一些原生属性可以利用,也有一些属性不能访问,是 js 引擎内部固有的隐式属性

    [[scope]] 就是 JS 内部隐式属性,是函数存储作用域链的容器

    function test() {
    
    }
    console.log(test.name); // test
    console.log(test.length); // 0

    https://www.houdianzi.com/ vi设计公司

    作用域链

    在函数声明时,生成 JS 内部隐式属性 [[scope]],该属性的第 0 位保存全局执行期上下文 GO 的一个引用

    在函数执行前一刻,[[scope]] 第 0 位保存函数执行期上下文 AO,后一位保存外层函数的 AO,最后保存 GO 引用。如果没有外层函数,则第 0 位 AO,第 1 位 GO。在寻找声明时,都会由 0 位向后寻找,即先看自己,再看外层,最后看全局

    在函数执行完毕时,从 [[scope]] 中销毁 AO

    function a() {
        funtion b() {
            var b = 2; // (3)
        }
        var a = 1; // (2)
        b(); 
    }
    var c = 3; // (1)
    a();
    // 全局预编译
    // -> GO{c: undefined, a: a(){}}
    // -> a.SCOPE = [
    //               GO{c: undefined, a: a(){}}
    //       ]
    // 全局执行
    // 执行 (1)
    // -> GO{c: 3, z a(){}}
    // -> a.SCOPE = [
    //               GO{c: 3, a: a(){}}
    //       ]
    // 执行到 a(),函数 a 预编译
    // -> a.SCOPE = [
    //               a_AO{a: undefined, b: b(){}}, 
    //               GO{c: 3, a: a(){}}
    //       ]
    // -> b.SCOPE = [
    //               a_AO{a: undefined, b: b(){}}, 
    //               GO{c: 3, a: a(){}}
    //       ]
    // 函数 a 执行
    // 执行 (2)
    // -> a.SCOPE = [
    //               a_AO{a: 1, b: b(){}}, 
    //               GO{c: 3, a: a(){}}
    //       ]
    // 执行到 b(),函数 b 预编译
    // -> b.SCOPE = [
    //               b_AO{b: undefined}, 
    //               a_AO{a: 1, b: b(){}}, 
    //               GO{c: 3, a: a(){}}
    //       ]
    // 执行 (3)
    // -> b.SCOPE = [
    //               b_AO{b: 3}, 
    //               a_AO{a: 1, b: b(){}}, 
    //               GO{c: 3, a: a(){}}
    //       ]
    // 函数 b 执行完毕,b_AO 销毁
    // -> b.SCOPE = [
    //               a_AO{a: 1, b: b(){}}, 
    //               GO{c: 3, a: a(){}}
    //       ]
    // 函数 a 执行完毕,a_AO 销毁
    // -> b.SCOPE 销毁
    // -> a.SCOPE = [
    //               GO{c: 3, a: a(){}}
    //       ]
  • 相关阅读:
    changing a pointer rather than erasing memory cells
    验证码识别 edge enhancement 轮廓增强 region finding 区域查找
    Manipulating Data Structures
    passing parameters by value is inefficient when the parameters represent large blocks of data
    Aliasing 走样
    Artificial Intelligence Research Methodologies 人工智能研究方法
    Thread safety
    include pointers as a primitive data type
    flat file
    functional cohesion
  • 原文地址:https://www.cnblogs.com/xiaonian8/p/15143755.html
Copyright © 2011-2022 走看看