最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 五.JS第一座大山:堆栈内存和闭包作用域

    正文概述 掘金(前端_阿珂)   2021-05-21   456

    一.词法解析和变量提升

    1.1 创建变量

    第二:var可以先使用,后声明;let必须先声明后使用。
    第三:var是允许在相同作用域内重复声明同一个变量的,而let与const不允许这一现象。
    第四:在全局上下文中,基于let声明的全局变量和全局对象GO(window)没有任何关系 ; var声明的变量会和GO有映射关系;
    第五:解决暂时性死区:

    第六:let /const/function会把当前所在的大括号(除函数之外)作为一个全新的块级上下文,应用这个机制,在开发项目的时候,遇到循环事件绑定等类似的需求,无需再自己构建闭包来存储,只要基于let的块作用特征即可解决

    1.2 变量提升

    • 带var的只是提前声明,没有赋值,默认值是undefined。
    • 带function的声明加赋值。
    • 不带var的a=3表示给全局设置window.a=3和在全局作用域下var a=3是一样的;
    //因为有变量提升机制,所以这段代码不会报错。
          console.log(foo);//undefined
          bar();//2
          var foo = 1;
          function bar() {
            if (!foo) {
              var foo = 2;
            }
            console.log(foo);
          }
    
          console.log(foo);//foo() {}
          function foo() {}
    
          console.log(foo);//undefined
          {
            function foo() {}
          }
    
          var a = 0;
          if (true) {
            a = 1;
            function a() {}//这前面的对a的操作映射一份给全局,后面的留给自己
            a = 11;
            console.log(a);//11
          }
          console.log(a);//1
    
          var a = 0;
          if (true) {
            a = 1;
            function a() {}
            a = 11;
            function a() {}//这前面的对a的操作映射一份给全局,后面的留给自己
            console.log(a); //11
          }
          console.log(a); //11
    
          {
            function foo() {
              alert("1");
            }
            foo = 1;
            function foo() {
              alert("2");
            } //把之前的对a的操作映射给全局一份(包括他自己也弄没了),后面的全是自己的
            foo = 2;
            console.log(foo); // => 2
          }
          console.log(foo); // => 1
    

    二.堆栈内存及垃圾回收机制

    堆内存:浏览器会把内置的属性和方法放到一个单独的内存中,

    js 中存在多种作用域(全局,函数私有的,块级私有的),代码执行前首先会形成自己的执行上下文,然后把上下文进栈,进栈后,在当前上下文再依次执行代码; 全局执行器上下文(EC(G))进栈(ECStack)执行,执行完代码就会把形成的上下文释放(出栈),当页面关闭全局上下文出栈;

    VO 变量对象:每一个执行上下文都会有自己的一个VO变量对象,用来存放在当前上下文中创建的变量和函数。(函数私有上下文叫 AO 活跃对象,但也是变量对象)。
    GO 全局对象:他是一个堆内存(存储的都是浏览器内置的 api 属性方法),在浏览器端,让 window 指向它
    VO(G)全局变量对象:全局上下文中用来存储全局变量的空间,他不是 GO=》只不过某些情况下 VO(G)中的东西会和 GO 中的东西有所关联而已;

    • 函数执行的时候,形成一个全新的私有上下文EC(FN),共字符串代码执行

    • 进栈执行,从上面进去,把全局往下压

    • 私有上下文有私有变量对象 AO(FN),在私有上下文中创建的对象会放到这里来;

    • 代码执行之前还需要:

      • 1.初始化作用域链(scopeChain):<EC(FN),EC(G)>
      • 2.初始化 this 指向:window
      • 3.初始化实参集合:arguments
      • 4.形参赋值
      • 5.变量提升
      • 6.代码执行

    垃圾回收机制

    2、浏览器垃圾回收机制/内存收机制:

    3、优化手段:内存优化 ; 手动释放:取消内存的占用即可。

    三.作用域和作用域链

    四.闭包及其两大作用:保护、保存

    我们把函数执行形成私有上下文,来保护和保存私有变量机制称为闭包

    五.高阶编程:多型函数、柯理化函数、compose组合函数

    六.BAT经典面试题

    • 题1:
          {
            function foo() {}
            foo = 1;
    
            console.log(foo);//1
          }
    
          console.log(foo);//function
    
    /*
          EC(G):{
                大括号中出现let/const/function...都会被认为是块级作用域;
                function的只提前声明,不会提前赋值;
             1. 变量提升:foo
             2. 代码执行:EC(block)块级作用域{
                            AO:      foo-----AF0  改foo=1
                           1 变量提升  foo
                           2 代码执行: function foo() { }  ==》AF0
                                           //foo在全局声明过,为了兼容es3,浏览器会把这行代                                         码之前对foo操作映射到全局  :把全局的foo---AF0
                                       foo = 1
              }
              代码执行2:console.log(foo);//function foo(){}
          }
          */
    
    • 题2:
          let x = 1;
          function A(y) {
            let x = 2;
            function B(z) {
              console.log(x + y + z);
            }
            return B;
          }
          let c = A(2);
          c(3); //==>7
    
    • 题3:
          let x = 5;
          function fn(x) {
            return function (y) {
              console.log(y + ++x);
            };
          }
          let f = fn(6);
          f(7); //14
          fn(8)(9); //18
          f(10); //  18
          console.log(x); //5
    

    五.JS第一座大山:堆栈内存和闭包作用域

    • 题4:
          let a = 0,
            b = 0;
          function A(a) {
            A = function (b) {
              console.log(a + b++);
            };
            console.log(a++);
          }
          A(1); //1
          A(2); //4
    

    五.JS第一座大山:堆栈内存和闭包作用域

    • 题5:
    var a = 10,
      b = 11,
      c = 12; //c=3
    function test(a) {
      a = 1;
      var b = 2;
      c = 3;
    }
    test(10);
    console.log(a, b, c);
    /*解析:
           EC(G)
           变量提升:a=10  ,b=11,c=12   ,
                    function test(){}   scope:EC(G)  形参:a  存放到AF0中
                     
           代码执行1:test(10)---AF0(10)
                    {
                        形参赋值:a=10  改a=1
                        变量提升:a=1(找到自己形参改), b=2,c=3(找到上级修改)
                        代码执行:
                    }
            代码执行2:console.log(a, b, c);//10,11,3         
    
          */
    
    • 题6:
    var a = 4;
    function b(x, y, a) {
      console.log(a);
      arguments[2] = 10;
      console.log(a);
    }
    a = b(1, 2, 3);
    console.log(a);
    //  3 10 undefined
    /*
          EC(G):{
              变量提升:a=4,
                       function b(){...}  scope:EC(G)  形参:x,y,a  存到AF0中
              代码执行:a=b(1,2,3)  -->a=AF0(1,2,3)  形成EC(A)
                       console.log(a)==>undefined
            }
                EC(A)私有上下文  进栈执行{
                    形参赋值:x=1,y=2,a=3,a=10
                    变量提升
                    代码执行: console.log(a);   ==>3
                              arguments[2] = 10;  a=10
                              console.log(a);   ==>10
                    函数执行完毕后返回给a=undefined          
                }    
          */
    
    • 题7:初始化实参集合
    function func(x, y, z) {
      x = 100;
      console.log(arguments[0]);
      y = 200;
      console.log(arguments[1]);
      z = 300;
      console.log(arguments[2]);
    }
    func(1, 2); //100 200 undefined
    /*
          执行函数时要初始化实参集合arguments:{0:10,1:20,length:2}
          形参赋值:x=10 ,y=20 ,z=undefined
          映射关系:x---argunments[0]
                   y---argunments[1]
                   z---argunments[2]
    */
    
    • 题8:
    var a = 9;
    function fn() {
      a = 0;
      return function (b) {
        return b + a++;
      };
    }
    var f = fn();
    console.log(f(5));
    console.log(fn()(5));
    console.log(f(5));
    console.log(a);
    /*
           EC(G)全局上下文:{
              VO:   a=9   fn=AF0   f=AF0()   a=0   f=BF0  a=1,a=0 ,a=1,a+1=2
    
              变量提升:a
              代码执行:f=fn() 
              形成EC(Fn)上下文:{
                            AO:
                            变量提升:
                            代码执行:a=0  //把全局的a改为0
                                      return function (b) {   return b + a++;   };把这个函数作为结果赋值给f=BF0
                          }
              } 
           AF0函数堆:{`
                     a = 0;
                     return function (b) {
                      return b + a++;
                     };
            `} 
            BF0函数堆:{`
                    function (b) {   return b + a++;   };
            `} 
         
            全局中代码执行1: console.log(f(5));
             {
                 console.log(f(5));相当于打印console.log(5+a++);//5+0=5
                 私有:b=5
                 全局:a=0 a++=0  然后把全局的a+1
                
             }
          
            全局中代码执行2:console.log(fn()(5));//5
            {
                执行fn(),又把a=0了,返回function (b) { return b + a++;};
                再把5传进去执行这个函数  5+0=5   全局下a+1
            }
            全局中代码执行3:console.log(f(5))// 5+1=6  全局a+1
            全局中代码执行4:console.log(a);//2
          */
    
    • 题9:
    var test = (function (i) {
      return function () {
        alert(i * 2);
      };
    })(2);
    test(5); //4
    
    • 题10:
    var x = 5,
      y = 6;
    function func() {
      x += y;
      func = function (y) {
        console.log(y + --x);
      };
      console.log(x, y);
    }
    func(4);
    func(3);
    console.log(x, y);
    /*
           EC(G)全局上下文:{
              VO:  x=5,y=6,func=BF0,x=11,x=10
              变量提升:x,y,func,
              代码执行:func(4)---AF0(4)
              形成EC(Fn)上下文:{
                            AO:
                            变量提升:
                            代码执行1:x+=y ==》x=11赋值给全局
                            代码执行2:func=BF0  形参:y
                            代码执行3:console.log(x, y);//输出11,6
                          }
               代码执行func(3)---BF0(3)
               形成EC(Fn1)上下文:{
                             AO:y=3
                            变量提升:
                            代码执行1:y+--x =3+10=13  全局x=10  //输出13
               }
               代码执行:console.log(x, y);//10,6
              } 
          AF0函数堆:{
               x += y;
               func = function (y) { console.log(y + --x);  };
               console.log(x, y);
          }
          BF0函数堆:{
              console.log(y + --x);
          }
          */
    
    • 题11:
    function fun(n, o) {
      console.log(o);
      return {
        fun: function (m) {
          return fun(m, n);
        },
      };
    }
    var c = fun(0).fun(1);
    c.fun(2);
    c.fun(3);
    /*
           EC(G)全局上下文:{
              VO: fun=AF0 ,c=fun(0).fun(1)[此刻要执行函数],c=BF0
              变量提升:fun,c,
              代码执行:c=fun(0).fun(1)--》AF(0).AF0(1)
              形成EC(Fn1)上下文:{
                            AO:n=1,o=0
                            变量提升:
                            代码执行1:console.log(o);//undefined
                            代码执行2:return {  fun: function (m) {return fun(m, n);  },返回了一个对象,形成一个对象堆存储BF0
                            代码执行3:BF0.fun(1)执行了BF0对象的fun方法,传参数1===》执行BF1(1)里面的函数
                            形成BF1(1)上下文:{
                                AO:m=1
                                变量提升:
                                代码执行:return fun(m, n) //m=1自己的,n=0上级的,==》return fun(1,0)===>0
                                         并且还返回了BF0对象给c
                            }
                        };
                            
                          }
              代码执行:c.fun(2);==>m=2,n=1==>fun(2,1)//1
              代码执行:c.fun(3);==>m=3,n=1==>fun(3,1)//1
    
                        } 
            AF0函数堆  形参为:n,o {
                console.log(o);
                return {  
                    fun: function (m) {return fun(m, n); },
                };
            } 
            BF0对象堆{
            `   fun: BF1    `
            }
            BF1函数堆{
                function (m) {return fun(m, n) 
            }
          */
    
    • 题12:
          let a = 1;
          function fn1() {
            let a1 = 2;
            function fn2() {
              let a2 = 3;
              function fn3() {
                let a3 = 4;
                a = a1 + a2 + a3;
                console.log(a);
              }
              fn3();
            }
            fn2();
          }
          fn1();//9
    
    • 题13:1.函数作为参数被传递
     let a = 100;
          function f1() {
            console.log(a);
          }
          function f2(f) {
            let a = 200;
            f();
          }
          f2(f1);//100
    
    • 题14:2.函数作为返回值被返回
    
    function create(){
        //函数时在这里面创建的,会优先使用这里面的数据
    let a=100
    return function(){
        console.log(a)
    }
    }
    let fn=create()
    let a=200
    fn();//100
    
    • 题15:3.闭包应用:隐藏数据,只提供api
     function createCache() {
            const data = {}; //隐藏起来了
            return {
              set: function (key, value) {
                data[key] = value;
              },
              get: function (key) {
                return data[key];
              },
            };
          }
          const c = createCache();
          c.set("a", 100);
          console.log(c.get("a"));
    
    • 题16:
    let a;
          for (let i = 0; i < 10; i++) {
            a = document.createElement("a");
            a.innerHTML = i + "<br>";
            a.addEventListener("click", function (e) {
              e.preventDefault();
              alert(i);
            });
            document.body.appendChild(a);
          }
    

    起源地下载网 » 五.JS第一座大山:堆栈内存和闭包作用域

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元