红宝书的说法: 变量和函数的上下文决定了它们可以访问哪些数据和它们的行为。每个上下文都有一个关联的变量对象,上面存着定义的变量与方法,无法通过代码访问,后台可以读取。
    函数也有其他属性并可以访问
    fn.name 函数名称
    fn.legnth 函数形参个数
    fn.prototype 函数的原型

    一、作用域
    函数创建时产生的隐式属性[[scope]]
    作用 :作用域明确了可访问变量和方法的范围。
    [[scope]]保存着scope chain作用域链,作用域链储存的是AO(函数执行上下文)或者GO(全局执行上下文)
    函数执行完后,AO会销毁,再调用时,重新创建,AO是即时容器
    GO 包含
    this -> window
    window -> object
    document -> object
    a ->
    AO 包含
    this -> 一般为window
    arguments -> 类数组
    a ->
    fn -> function
    AO创建过程

    1. function test (a){
    2. var b = 123;
    3. function b (){
    4. }
    5. console.log(a,b)
    6. }
    7. test()
    8. 1、给AO添加形参属性,值为undefined
    9. 2、给AO添加自定义变量和函数表达式属性,值为undefined
    10. 3、给形参赋值
    11. 4、函数声明
    12. 5、执行其余代码

    一个函数创建的时候作用域链中已经包含了GO全局执行上下文和上级AO,作用域链和外层作用域链一样。
    被调用后,预编译的时候,才形成自己的AO,排在作用域链最前面。

    1. function a (){
    2. function b (){}
    3. }
    4. a()

    b函数执行完了以后,OA销毁,作用域链回到定义时的状态。a执行完以后,a的AO销毁,AO的b属性也消失了,所以b函数没了。
    为什么函数外部不能访问函数内部变量,因为函数外部作用域链中,没有包含函数内部的AO执行期上下文。
    为什么函数内部可以访问函数外部变量,因为函数内部作用域链中包含了外层的AO执行期上下文