JS作用域与词法分析

一、作用域&作用域链

JS的作用域是通过函数划分的,函数的作用域在定义阶段就已经确定:

  1.在最外层函数和在最外层函数外面定义的变量拥有全局作用域

var name="amos";

    function foo(){
        var age=18;
        function inner(){
            console.log(age);
        }

        inner();
    }

    console.log(name);    // amos
    //console.log(age);   // Uncaught ReferenceError: age is not defined
    foo();                // 18
    inner();              // Uncaught ReferenceError: inner is not defined

  2.所有未定义直接赋值的变量自动声明为拥有全局作用域,例如:

  变量age拥有全局作用域,而sex在函数外部无法访问到

var name="amos";

    function foo(){
        age=18;
        var sex="male"
    }

    foo();
    console.log(age);   //  18
    console.log(sex);   // sex is not defined

  3.所有window对象的属性拥有全局作用域

  一般情况下,Window对象的内置属性都拥有全局作用域。例如window.alert()、window,location、window.top等。

  4.在函数内部定义的变量,拥有局部作用域

二、AO对象&词法分析

  JS代码运行分为两个阶段:先进行词法分析,再执行。

  一个函数被调用的一瞬间,产生一个活动对象AO(Active Object),词法分析会为该对象填充属性。

  词法分析根据作用域链,从外到里进行分析,分为三步:

  1.分析形参/实参

  2.分析var声明的变量(注意,变量的值是在执行时候决定的)

  3.分析函数声明

  示例演示:

//-----**********************例1*********************************

var s=12;
    function f(){
        console.log(s);
         var s=12;          // if s=12
        console.log(s)
    }
    f();

// undefined
// 12

//-----**********************例2*********************************

var s=10;
function foo(){
  console.log(s);
  var s=5;
  console.log(s);
  function s(){console.log("ok")}// 函数的定于或声明是在词法分析时完成的,执行时已不再有任何操作

  console.log(s);
}

foo();

// function s
// 5
// 5
//-----***********************例3********************************

function bar(age) {

        console.log(age);
        var age = 99;
        var sex= 'male';
        console.log(age);
        function age() {
            alert(123)
        };
        console.log(age);
        return 100;
}

result=bar(5);

  我们以最复杂的第三个例子来解析一下整个过程:

  1、调用bar函数的瞬间,生成AO对象,

  2、分析形参/实参:

    1)函数声明时的形参,作为AO的属性,默认值undefined,即AO.age = undefined

    2)接收实参5,给AO.age属性赋值,即AO.age = 5

  3、分析变量声明:

    1)如果AO还没有该属性,添加;如果有(相当于重新声明),不执行任何操作,原来的值不做任何修改

    2)第3行,找到声明var age,判断已经存在AO.age,不作任何处理

    3)第4行,找到声明var sex,添加AO.sex = undefined

  4、分析函数声明:

    1)如果AO还没有该属性,添加;如果有,则直接覆盖。

    2)第7行,找到function age( )声明,而原来AO.age=5,直接被覆盖为AO.age = function age( )。

  5、执行过程:

  1. 执行第2行 console.log(age)时,当前AO.age = function age( ) ,所以输出函数
  2. 执行第3行,age = 99 时,对AO.age赋值 99
  3. 执行第4行,sex = 'male'时,对AO.sex赋值 male
  4. 执行第5行,console.log(age)时,AO.age = 99 —— 输出99
  5. 注意!第7行 function.age( ) 函数声明,不进行任何操作,因为词法分析阶段已经完成了。
  6. 执行第11行,console.log(age)时,AO.age还是99——输出99
  7. foo函数返回100

 

posted @ 2017-10-22 13:45  Amos丶G  阅读(157)  评论(0编辑  收藏  举报