• js之堆、栈内存基础


    函数渲染规则

    全局作用域:当浏览器打开页面时,浏览器会给当前JS代码提供一个可以执行的运行环境,那么这个环境就是全局作用域。

    • 一个页面只对应一个全局作用域;在当前的全局作用域,浏览器给当前作用域提供了全局的对象叫window
    • JS是单线程的,每次只能执行一行代码。
    • 在JS中只要遇到报错,代码立即停止,不再向下执行。

    全局变量:在全局作用域定义的变量都是全局变量。全局变量都会给window新增一个键值对。

    私有变量:在私有作用域中定义的变量;

    • 外层作用域获取不到私有作用域下的变量;
    • 形参也是私有变量;
    • 在私有作用域下定义的也是私有变量。

    闭包:函数执行会形成一个私有的作用域,保护里面的变量不受外界干扰。

    在原有浏览器渲染机制下(ES6之前),基于typeof等逻辑运算符检测一个未被声明过得变量,不会报错,返回undefined;ES6版本直接报错

    变量提升

    在当前作用域下,代码执行之前,把当前作用域下带var和function的要进行提前声明(通知当前作用域有这么一个变量),带var的只声明不定义,function不仅声明而且还要定义(赋值)。

    变量提升五种特殊情况

    1. 如果有条件,不管条件是否成立,都要进行变量提升;对于function函数,在最新的版本浏览器中,只声明不定义;在旧版本浏览器中,带function的不仅声明,还要定义。

    在块级作用域下,定义的函数,只要一进块级作用域,它会立即开辟空间,并且赋值。

        console.log(num);//undefined
        console.log(ef);//undefined
        if([]){
            console.log(ef);//整个函数
            var num=100;
            function ef(){
    
            }
        }
    
    1. 变量提升只发生在等号的左边。
    var fn=function fn1(){
    
    }
    //等号的右边不会发生变量提升,只有执行到这一行时,右边函数才开始开辟堆内存。
    
    1. return下面的代码需要进行变量提升;但是如果return后面紧跟的代码(返回的值)不进行变量提升。
    2. 如果变量名重复,不需要重新声明,但是要重新定义。(不管是变量提升还是代码执行阶段都是如此)
    //例1
        console.log(fn);  //函数本身
        var fn = 88;
        function fn() {
        }
        console.log(fn);//88
    //例2
        fn();//3
        function fn() {//在变量提升阶段已经对这段代码解析过了,代码运行时,不再解析
            console.log(1);
        }
        fn();//3
        function fn() {
            console.log(2);
        }
        fn = 100;//变量提升阶段不提升
        function fn() {
            console.log(3);
        }
        fn();//报错
    
    1. 匿名函数不需要进行变量提升。当代码解析到匿名函数时,会先开辟一个堆内存,然后马上形成一个栈内存。

    在ES6:ECMAScript中:
    let声明变量

    1. let声明的变量不进行变量提升
    2. 在同一作用域下,let声明的变量不可以重名
    3. ES6中,块级作用域:if...else...、for、while...,唯独对象的大括号不是块级作用域

    上一级作用域

    当获取变量对应值时,如果当前作用域不存在,需要向上一级作用域查找。
    函数的上一级作用域跟函数在哪执行没关系,跟函数在哪定义有关,函数在哪个作用域下定义,上一级作用域就是谁。

    作用域链:当获取变量值时,首先会看自己私有作用域有没有,如果没有,需要向上一级作用域查找,如果上一级 也没有,需要再向上一级查找,指导找到全局作用域为止,如果全局作用域也没有,那就报错,这样一级一级向上查找形成一条作用域链。

    堆内存与栈内存

    在JS中,浏览器会形成两个虚拟的内存:栈内存和堆内存

    堆内存

    主要用来存储引用数据类型内容的。

    栈内存:作用域

    1. 提供了代码的运行环境;
    2. 存储基本数据类型值。

    堆内存的销毁

    堆内存的回收

    • 谷歌浏览器:每隔一段时间会对引用类型的空间地址进行检测,检测当前地址有没有被占用;如果没有被占用,那么将其回收;如果占用,不能回收。
    • 火狐和IE:采用了计数的规则,当前的引用地址被占用一次,就会+1;如果不再占用,就会-1;如果当前地址被占用次数为0,那么浏览器将其立即回收。

    栈内存的销毁

    全局作用域的销毁

    全局作用域只有当关闭页面或关闭浏览器时,才会销毁;属于不销毁的作用域。

    作用域一旦销毁,那么作用域所提供的代码运行环境也会随着销毁,而且存储的基本数据类型值也会随着回收。

    私有作用的销毁

    • 函数执行会产生私有作用域;
    • 函数每执行一次,都会形成一个新的栈内存;

    立即销毁的作用域

    一般情况下,函数执行完毕,浏览器会对其栈内存立即进行回收,这就是立即销毁的作用域。

    不销毁的作用域

    满足两个条件:

    1. 函数执行返回一个引用数据类型的值;
    2. 返回的引用数据类型值一定要被外界接收;
    //不销毁的作用域
    var total=10;
    function s(){
         //s形成的作用域是不销毁的;
          var total=100;
          return function(){  //满足条件1
              //执行完,就销毁
              console.log(total);//100
          }
    }
    var f=s();//满足条件2
    f();
    

    不立即销毁的作用域

    //不立即销毁的作用域
    function s(){
         //此处s形成的作用域不立即销毁,它会等到里面小函数执行完成之后,销毁当前的作用域
          var total=100;
          return function(){ 
              console.log(total);//100
          }
    }
    s()();
    
        var num = 1;// 2
        var  obj = {
            //这不是一个作用域;
            num : 10,
            // fn的属性值是自执行函数的返回值;
            fn : (function () {
                // 自执行函数的上一级作用域是全局作用域
                // 当代码解析到这一行时;
                // 在执行自执行函数时,obj没有空间地址;
                // 当obj以键值对存储时,obj现在没有空间地址,执行了这个自执行函数;
                   return function(n){
                       console.log(n+(++num))
                   }
                })()// obj --> undefined
        }
        var f = obj.fn;
        f(10);// 12
        f(20);// 23
        obj.fn(30);// 34
        obj.fn(40);// 45
    

    this

    this——关键字,在JS中有特定的意义;

    1. 全局作用域下的this指向window;和window是同一个空间地址。
    2. 如果给元素的事件行为绑定函数,那么函数中的this指向当前被绑定的那个元素。
    3. 函数中的this,要看函数执行前有没有 “.”,有点的话,点前面是谁,this就指向谁,如果没有点,那么会指向window。
    4. 自执行函数中的this永远指向window。
    5. 定时器中函数的this指向window。
    6. 构造函数中的this指向当前的实例。
    7. call、apply、bind可以改变函数中的this指向。
  • 相关阅读:
    day113-django-Form组件常用字段和参数
    day112-django-Form组件-ajax提交给后台的Form验证
    day110-django-中间件和(socket:wsgiref、uwsgi)
    day111-django-初识Form组件(验证登录信息)
    day109-django-多对多、session保存用户信息到数据库和从数据库获取用户信息
    day108-django-路由分发、动态路由、伪静态、根据名称反向生成url
    软件测试基础
    Python并发编程之:多进程
    进程介绍(理论部分)
    网络编程
  • 原文地址:https://www.cnblogs.com/wangxingren/p/10188701.html
Copyright © 2020-2023  润新知