JavaScript作用域

147 阅读3分钟

作用域

1、作用域的深刻理解

执行期的上下文 当函数代码执行的前期,会创建一个执行器上下文的内部对象 AO (AO为真正的作用域)

这个内部的对象是预编译的时候创建的,因为当函数被调用的时候,会先进行预编译

在全局代码执行的前期会创建一个执行器的上下文的对象GO

2、作用域的浅理解

全局作用域

1、全局作用域在页面打开时被创建,页面关闭时被销毁
2、script 标签中的变量和函数,作用域为全局,在页面任何位置可以访问到
3、在全局作用域中有全局对象window,代表一个浏览器窗口,由浏览器创建,可以直接调用
4、全局作用域中声明的变量和函数会作为window对象的属性和方法保存

全局作用域预编译

1、创建 GO 对象
2、找变量声明,将变量名作为 GO 对象的属性名,值为undefined 
3、找函数声明,值赋予函数体

函数作用域

1、调用函数时,函数作用域被创建,函数执行完毕,函数作用域被销毁
2、每调用一次函数就会创建一个新的函数作用域,他们之间是互相对立的
3、函数作用域中可以访问当全局作用域的变量,在函数外无法访问到函数作用域内的变量
4、在函数作用域中访问变量、函数时,会先在自身作用域中寻找,若没有找到,则会在函数的上一级作用域中寻找,直到全局作用域

函数作用域预编译

1、创建 AO 对象
2、找形参和变量声明,将变量和形参名,当作 AO 对象的属性名,值为 undefined
3、实参形参统一
4、在函数体内找函数声明,值赋予函数体

备注:创建的预编译对象,全局叫 GO ,函数内部的叫 AO

// 预编译 示例
function fn(a,c) {
    console.log(a); // function a () {}
    var a = 123;
    console.log(a); // 123
    console.log(c); // function c () {}
    function a () {}; // (此为函数声明)
    if(false) {
        var d = 678;
    }
    console.log(d); // undefined
    console.log(b); // undefined
    var b = function () {}; // (此为函数的表达式,不是函数的声明)
    console.log(b); // function () {}
    function c () {}; // (此为函数声明)
    console.log(c); // function c () {}
}

fn(1,2)

// 解析 预编译
1、创建 AO 对象
2、找形参和变量声明,将变量和形参名,当作 AO 对象的属性名,值为 undefined (不用考虑是否能进入判断条件)
3、实参形参统一
4、在函数体内找函数声明,值赋予函数体
AO {
    // 变量声明 : 值 : 参数统一 :值赋予函数体
    a : undefined : 1function a () {}
    c : undefined : 2 :  function c () {}
    d : undefined 
    b : undefined
}
3、实参形参统一

作用域链

会被保存到一个隐式的属性中,[[scope]] 这个属性是我们用户访问不到的,但确实存在的,让 js 引擎来访问,里面存储的就是作用域链 AO、GO、AO 和 GO集合

// 作用域链 示例
var global
function a () {
    // a 执行 b才定义
    function b () {
        // 首先 b 函数的 AO,a 函数的 AO,最后是全局的 GO
        var bb = 123;
        aa = 0;
    }
    var aa = 123
    b()
}

a()

image.png