为什么了解AO GO:为了解决作用域、作用域链相关所产生的一切问题 AO -> function 相当于独立的仓
库 互相不影响

(1)作用域

  1. 对象

    • 函数也是一种对象类型、引用类型、引用值

      1. function test(a, b){
      2. }
    • 可以访问的属性 test.length test.name test.protoytpe 注 函数名.length 是指形参的长度

    • 对象 -> 有些属性使我们无法访问的

Js引擎内部固有的隐式属性
2. [[scope]] 域
1. 函数创建时,生成的的一个JS内部的隐式属性,只能JS引擎读取
2. 函数用来存储作用域链的容器,作用域链(AO、GO)

  1. - AO:函数的执行期上下文
  2. - GO:全局的执行期上下文
  3. - 函数执行完成后,AO是被销毁的,
  4. - 如果再次执行这个函数的时候会重新生成一个全新的AO,
  5. - AO 是一个即时的存储容器

(2)作用域链

            function a() {
                function b() {
                    var b = 2;
                }
                var a = 1;
                b();
            }
            var c = 3;
            a();

页面打开的时候全局已经在执行,在执行的前一刻会生成GO -> 函数声明已经定义 全局执行的时候函数表达式
才赋值
1. 当函数 a 被定义的时候,

  • 系统生成一个[[scope]]属性,[[scope]]中保存该函数的作用域链
  • 在作用域链的第0位保存当前环境下的全局执行上下文GO
  • GO 中保存全局下的所有对象,其中包含函数a 和全局变量c = 3
  1. 当函数 a 函数被执行时(前一刻,预编译的时候)

    • 系统生成一个[[scope]]属性,保存该函数的作用域链
    • 作用域链的顶端(第0位)保存a 函数生成的函数执行期上下文 AO
    • GO 被保存到 作用域链的第1位
    • 查找变量是从a 函数的作用域从顶端往下依次查找
  2. a 在执行的同时函数 b 函数被定义时,

    • 在a函数环境下,b 函数在定义的时候和a 函数被执行的时候作用域链是相同的
  3. 当函数 b 函数被执行时(前一刻,预编译的时候)

    • 系统生成一个[[scope]]属性,保存该函数的作用域链
    • 第 0 位保存自身的AO,a 函数的AO和全局的Go依次向下排列
  4. 当函数 b 函数执行结束的时候

    • b 函数的AO 被销毁,回归b 被函数定义的时候的[[scope]]
  5. 当函数a 执行结束的时候

    • 函数a 的 AO 被销毁 同时 b 函数的[[scope]]也销毁了
    • a 函数 回归 a函数 被定义的时候
             function a() {
                 function b() {
                     function c() {
                     }
                     c();
                 }
                 b();
                 console.log(b)
             }
             a();
           // 1. a 定义:a.[[scope]] -> 0 : GO
           // 2. a 执行:a.[[scope]] -> 0 : a.ao 1 : Go
           // 3. b 定义:b.[[scope]] -> 0 : a.ao 1 : Go
           // 4. b 执行:b.[[scope]] -> 0 : b.ao 1 : a.ao 2 : Go
           // 5. c 定义:c.[[scope]] -> 0 : b.ao 1 : a.ao 2 : Go
           // 6. c 执行:c.[[scope]] -> 0 : c.ao 1 : b.ao 2 : a.ao 3. Go
           // 7. c 销毁:c.[[scope]] -> 0 : b.ao 1 : a.ao 2 : Go
           // 7. b 销毁:b.[[scope]] -> 0 : a.ao 1 : Go
           // 7. a 销毁:a.[[scope]] -> 0 : GO
      

      (3)闭包基础

      闭包就是能够读取其他函数内部变量的函数
             function test1() {
                 var c = 3;
                 function test2() {
                     var b = 2;
                     a++;
                     console.log(a);
                 }
                 var a = 1;
                 return test2;
             }
             var c = 3;
             var test3 = test1();
             test3();
      
  6. 闭包
    当内部函数被返回到外部并保存时,一定会产生闭包
    闭包会产生原来的作用域链的不释放
    过度的闭包可能会导致内存的泄露,或者加载太慢

    闭包demo

     // 非闭包写法
     var count = 0;
     window.onload = function(){
         var button = document.getElementById("clickme");
         button.onclick = handleClick;
     }
     function handleClick(){
         var message = "you click me";
         var div = document.getElementById("message");
         count++;
         div.innerHTML = message + count + "times!";
     }
     // 非闭包写法 count必须写在外面 不然每次都会进入函数重置 但是会引起变量重名的问题 
    
     // 闭包写法
     window.onload = function (){
         var count = 0;
         var message = "you clicked me";
         var div = document.getElementById("message");
         var button = document.getElementById("clickme");
         button.onclick = function () {
             count++;
             div.innerHTML = message + count + "times!";
         }
     }
    

    闭包实例

    返回数组写法

     function test(){
         var n = 10;
         function add(){
             n++;
             console.log(n);
         }
         function reduce(){
             n--;
             console.log(n);
         }
         return [add,reduce];    //此处返回的是数组则下面的arr被赋值的就是数组
     }
     var arr = test();
     console.log(arr);
    
     //返回数组写法
    
     arr[0]();
     arr[1]();
    

    返回对象写法

     function test(){
         var n = 10;
         function add(){
             n++;
             console.log(n);
         }
         function reduce(){
             n--;
             console.log(n);
         }
          return {add,reduce}; //此处返回的是对象则下面的arr被赋值的就是对象
     }
     var arr = test();
     console.log(arr);
    
     // 返回对象写法
    
      arr.add();
      arr.reduce();
    

    返回整个数组写法

                 function test2() {
                     var sunSched = '';
                     var operationarr = [
                         function setSched(thing) {
                             sunSched = thing;
                         },
                         function showSChed() {
                             console.log("my" + sunSched);
                         }
                     ]
                     return operationarr; //直接返回整个数组写法
                 }
                 var sunSched = test2();
                 console.log(sunSched);
                 sunSched[0]('thing');
                 sunSched[1]();
                 sunSched[0]('test1');
                 sunSched[1]();
    

    返回整个对象写法

         function test() {
             var sunSched = '';
             var operation = {
                 setSched: function (thing) {
                     sunSched = thing;
                 },
                 showSChed: function () {
                     console.log("my" + sunSched);
                 }
             }
             return operation; //直接返回整个对象
         }
         var sunSched = test();
         sunSched.setSched('test1');
         sunSched.showSChed();
    

相关课件

相关课件

作用域图解.pptx