zoukankan      html  css  js  c++  java
  • javaScript基础知识--变量提升和闭包

    1 变量的提升

      当浏览器开辟出提供代码执行后的栈内存后,代码并没自上而下的立即开始执行,而是继续做了一些事情

       1 把当前作用域中所有带 var / functiong关键字的进行了提前的声明和定义,这称为js的变量提升机制

         其中,使用var 声明的z只是提前声明,并没有进行赋值,没有赋值,默认值为 undefined

                 使用functiond的不仅声明了,而且还进行了定义 ,让变量和某个值进行关联。

     2 带 var 和 不带 var 的区别?

    //=>在全局作用域下的区别
    /*
     * 不带var的:相当于给全局对象window设置了一个属性a
     *    window.a = 13;
     */
    a = 13;
    console.log(a); //=>window.a
    
    
    /*
     * 栈内存变量存储空间
     *    b
     * 带var的:是在全局作用域下声明了一个变量b(全局变量),但是在全局下声明的变量也同样相当于给window增加了一个对应的属性(只有全局作用域具备这个特点)
     */
    var b = 14; //=>创建变量b & 给window设置了属性b
    console.log(b); //=>14
    console.log(window.b); //=>14

    闭包作用域:

      1 创建函数阶段:

        开辟一个堆内存空间,把函数体中的代码当作字符串存储进去,然后把它对应的堆内存的地址,赋值给函数名/变量名

       函数在那创建,那么它执行时候所需要查找的上级作用域就是谁

        2 函数执行阶段:

        1 会形成一个全新的私有栈内存,执行上下文,私有栈内存,

                  (每执行一次,就会形成一个新的私有作用域,多个作用域之间不会相互影响)

                2 进行形参 赋值 和 变量提升的 操作。

        3 代码的执行(会把之前保存存在堆内存中的字符串拿出来按照顺序一行行的执行)。

           4  遇到一个变量,首先看它是否为 私有变量(形参和在私有作用域中声明的变量是私有变量),如果是

        私有的变量就操作自己的变量即可,不是私有的则向上级作用域中查找...一直找到全局作用域为止,这种机制

        称为JS的z作用域链查找机制

        3 关于堆栈内存释放问题(以谷歌webkit内核为例子)

        函数执行就会形成栈内存,(从内存中分配的一块空间)。如果内存都不销毁释放,很容易就会导致

        栈内存溢出,(内存爆满,电脑就卡死了)。

         

      堆内存释放的问题

    //=>创建一个引用类型值,就会产生一个堆内存
    //如果当前创建的堆内存不被其它东西所占用了(浏览器会在空闲的时候,查找每一个内存的引用状况,不被占用的都会给回收释放掉),则会释放
    let obj = {
       name : 'zhufeng'
    };
    let oop = obj;
    //此时obj和oop都占用着对象的堆内存,想要释放堆内存,需要手动解除变量和值的关联(null:空对象指针)
    obj = null;
    oop = null;

      栈内存的释放

    //=>打开浏览器形成的全局作用域是栈内存
    //=>手动执行函数形成的私有作用域是栈内存
    //=>基于ES6中的let/const形成的块作用域也是栈内存
    //=>....
    
    /*
    * 全局栈内存:关掉页面的时候才会销毁
    * 私有栈内存:
    *    1.一般情况下,函数只要执行完成,形成的私有栈内存就会被销毁释放掉(排除出现无限极递归、出现死循环的模式)
    *    2.但是一旦栈内存中的某个东西(一般都是堆地址)被私有作用域以外的事物给占用了,则当前私有栈内存不能立即被释放销毁(
    特点:私有作用域中的私有变量等信息也保留下来了) =>也有人认为的闭包就是:函数执行形成不能被释放的私有栈内存,这样的才是闭包
    */ function fn(){ //... } fn(); //=>函数执行形成栈内存,执行完成栈内存销毁 function X(){ return function(){ //... } } let f=X(); //=>f占用了X执行形成的栈内存中的一个东西(返回小函数对应的堆),
    则X执行形成的栈内存不能被释放了

    4 let / const 和 var 的区别?

        1 leth和 constb不存在 变量提升的机制

        创建变量 6 种方式中,var / function 有变量提升,而 let /const /class / import  都不存在这个机制

        

        2 var允许变量重复的声明,而 let 是不允许的

            在相同的作用域中,(或者执行上下文)

          如果使用 var / function  关键词声明变量并且重复声明,是不会有影响的,

          (声明第一次之后,之后再遇到就不再重复声明了)

          但是使用 let /const  就不行了浏览器会检验当作用域中是否已经存在这个变量了,如果已经存在了,

          再次基于let  等于重新声明就会报错

        

    //=>在浏览器开辟栈内存供代码自上而下执行之前,不仅有变量提升的操作,
    还有很多其它的操作=>“词法解析”或者“词法检测”:就是检测当前即将要执行的代码是否会出现“语法错误 SyntaxError”,如果出现错误,代码将不会再执行(第一行都不会执行)
    console.log(1); //=>这行代码就已经不会再被执行了 let a = 12; console.log(a); let a = 13; //=>Uncaught SyntaxError: Identifier 'a' has already been declared console.log(a); //=>所谓重复是:不管之前通过什么办法,只要当前栈内存中存在了这个变量,
    我们使用let/const等重复再声明这个变量就是语法错误
    console.log(a); var a = 12; let a = 13; //=>Uncaught SyntaxError: Identifier 'a' has already been declared console.log(a);

     3 let 能解决 typeof 检测时出现的暂时性死区的问题

     

    // console.log(a); 
    //=>Uncaught ReferenceError: a is not defined
    
    // console.log(typeof a); 
    //=>"undefined" 这是浏览器BUG,本应该报错因为没有a(暂时性死区)
    
    console.log(typeof a); 
    //=>Uncaught ReferenceError: Cannot access 'a' before initialization
    let a;

        

  • 相关阅读:
    【codecombat】 试玩全攻略 第二章 边远地区的森林 一步错
    【codecombat】 试玩全攻略 第十八关 最后的kithman族
    【codecombat】 试玩全攻略 第二章 边远地区的森林 woodlang cubbies
    【codecombat】 试玩全攻略 第二章 边远地区的森林 羊肠小道
    【codecombat】 试玩全攻略 第十七关 混乱的梦境
    【codecombat】 试玩全攻略 第二章 边远地区的森林 林中的死亡回避
    【codecombat】 试玩全攻略 特别关:kithguard斗殴
    【codecombat】 试玩全攻略 第二章 边远地区的森林 森林保卫战
    【codecombat】 试玩全攻略 第二章 边远地区的森林
    实验3 类和对象||
  • 原文地址:https://www.cnblogs.com/wjgbok/p/11278963.html
Copyright © 2011-2022 走看看