zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Xcode官方下载地址
    IOS9 Swift
    IOS常用框架
    JS 阻止事件冒泡
    ASP.NET MVC验证DateTime的问题
    如何将图片嵌入到Html中
    Linq使用中的ToList注意事项
    LINQ to Entity里面不能使用DateTime
    SQL Procedure Operations
    Windows Service Operations
  • 原文地址:https://www.cnblogs.com/78pikaqiu/p/7709461.html
Copyright © 2011-2022 走看看