垃圾回收机制GC和闭包和沙盒模式

160 阅读5分钟

垃圾回收机制

/*
    1.GC回收
    2.作用域链 下级作用域能够访问上级作用域变量,上级作用域无法访问下级
    3.如何能够在函数外部访问内部变量呢?
    4.通过直接return内部变量在外部访问 只是访问当次函数执行的结果(值)
    没有办法对变量进行修改和存储
    
    5.不会被回收的持有状态  局部变量不在被需要的时候在当前栈中
    
*/

4.通过直接return内部变量在外部访问 只是访问当次函数执行的结果(值) 没有办法对变量进行修改和存储

function a(){
  let x = 10
  x++
  return x
}
a()//11
a()//11
function fn(){

    var w = 10

    return function fn1(){

      w++

      console.log(w)

    }

  }

  //1.fn()() //这样是立即执行结束 w会被回收


  //2.此时 w被fn1持有了  并且没有立即执行 w不会被回收

  //fn()//fn1() 但这种办法 终归会执行内部的 还是会被回收
 
 
  //3.
  //let x = fn() //此时  x持有fn1 包括内部的变量   x相当于第三方
  
  let x = fn()
  let y = fn()
  x()//11
  x()//12
  x()//13
  y()//11
  //x y 是分别拷贝 两个之间没有什么关系
 垃圾回收机制 垃圾QG回收
        函数没有执行的时候 

          有对应的函数存储空间存放函数内容体(不解析)
          函数开始执行的时候 会解析内容 根据内容 声明变量赋予空间
          函数执行完成之后 私有局部变量的地址空间会被回收
          (内部私有变量在没有被需要 或 期望被需要)
let test = {
  name: "isboyjc"
};
test = [1,2,3,4,5]
/*
首先我们声明了一个变量 `test`,它引用了对象 `{name: 'isboyjc'}`,接着我们把这个变量重新赋值了
一个数组对象,也就变成了该变量引用了一个数组,那么之前的对象引用关系就没有了,没有了引用关系,也就是
无用的对象,这个时候假如任由它搁置,一个两个还好,多了的话内存也会受不了,所以就需要被清理(回收)
*/
 
function a(){
      var x = 1
      x++
      console.log(x)
}
a()//2
a()//2
a()//2
a()//2
//函数执行结束后 函数内部的局部变量被回收了 

//形成了闭包 不会回收 a() 和 return出去的函数都在调用x 两个函数没有执行结束 瞬间
function a(){
      var x = 1
      return function (){
      x++
      console.log(x)
      }      
}
var w = a()
console.log(w())//2
console.log(w())//3
console.log(w())//4
console.log(w())//5

//会被回收 a()() 两个函数 瞬间一起执行结束 x被回收
function a(){
  var x = 1
  return function (){
    x++
    return x
  }
}
var w = a()()
console.log(a()())//2
console.log(a()())//2
console.log(a()())//2
console.log(a()())//2

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 在 JavaScript 内存管理中有一个概念叫做 可达性,就是那些以某种方式可访问或者说可用的值,它们被保证存储在内存中,反之不可访问则需回收

至于如何回收,其实就是怎样发现这些不可达的对象(垃圾)它并给予清理的问题, JavaScript 垃圾回收机制的原理说白了也就是定期找出那些不再用到的内存(变量),然后释放其内存

闭包

闭包情况下 不会产生垃圾回收

//形成了闭包 不会回收 a() 和 return出去的函数都在调用x 两个函数没有执行结束 瞬间
//三方的关系  w拿到了 return 函数 
function a(){
      var x = 1
      return function (){
      x++
      console.log(x)
      }      
}
var w = a()
console.log(w())//2
console.log(w())//3
console.log(w())//4
console.log(w())//5

一定要避免无意产生的闭包

<div class="btn">按钮</div>
  <div class="btn1">按钮1</div>
  <script>
    let oBtn = document.querySelector('.btn')
    let oBtn1 = document.querySelector('.btn1')
    /*

      点击按钮之后 按钮一 开放 输出num++

    */

    oBtn.addEventListener('click',function(){
      let num = 0
      oBtn1.addEventListener('click',function(){
        num++
        console.log(num)
      })
    })
    /*
      addEventListener 可以给一个时间添加相同事件

      每点击一次按钮 就给按钮1创建一个点击事件


      num 不会被回收 因为是被持有状态

      当按钮1被点击的时候 虽然执行结束了 但jc指向断开了

      再次点击按钮 又绑定了一个新的按钮1


      绑定两次了 相当于两个按钮1

      num 永远不会被回收了
      无法主动回收 因为是匿名的 
     

    */

  </script>

沙箱模式

  1. 实现JS在线编辑器:可以把用户输入的代码放到沙箱中运行,以免用户输入的信息影响页面的运行。
  2. 服务端渲染:例如在vue服务端渲染时,服务端会利用node中的vm创建一个沙箱,将前端的bundle代码放入沙箱中运行,以免影响node服务的正常运行。
  3. vue模板中表达式计算:vue模板中表达式的计算被放在沙盒中,只能访问全局变量的一个白名单,如 Math 和 Date 。你不能够在模板表达式中试图访问用户定义的全局变量。

沙箱的应用还有很多,这里也不一一列举了,总之,沙箱的作用就是创建一个相对独立的环境用来运行不可信的代码或程序

利用间接返回一个函数,然后去拿到外部函数内的私有变量

    function outer() {
            let a = 100
            let str = '张三'
​
            const obj = {
                getA: function () {
                    return a
                },
                getStr: function () {
                    return str
                },
                setA(val) {
                    a = val
                }
            }
​
            return obj
        }
          // 1. 调用了 外部函数 outer , 这个函数内部会返回一个 对象 obj, 然后我将她存储到了 变量 res
        let res = outer()
        console.log(res)
​
        let num = res.getA()
        // console.log(num)    // 100
​
        let newStr = res.getStr()
        // console.log(newStr) // '张三'
​
        res.setA(999)
        // console.log(res.getA()) // 999
​
​
        // 2. 调用了 外部函数 outer, 这个函数内部会返回一个对象 obj, 然后我将它存储到了 变量 res2 中
        let res2 = outer()
        console.log(res2.getA())    // 100

沙箱模式语法糖

  1. 沙箱模式语法糖: 再不影响功能的情况下,对我们的语法做一点简化操作 ES6
  2. 通过 getter 和 setter 帮助我们简化代码书写
     function outer() {
            let a = 1
            let b = 100
​
            const obj = {
                get a () {
                    return a
                },
                set a (val) {
                    a = val
                },
                get b () {
                    return b
                },
                set b (val) {
                    b = val
                }
            }
​
            return obj
        }
        let res = outer()
        // console.log(res.getA())  // 这样使用 有问题
        console.log(res)
        console.log(res.a)
        res.a = 999
​
        console.log(res.a)
​
​
        console.log(res.b)