JS的回收机制和闭包

本篇内容:

作用域及声明

JS作用域:全局、块、函数作用域。

在函数外,使用 var声明的变量为global variable

在函数内,使用 var声明的变量为local variable

letconst声明的变量为块作用域变量。

隐式声明的变量:是全局对象的属性。

js赋值操作的实质

1. 作用域链

JavaScript代码在执行时,会形成一个作用域链,该链包含当前执行代码的所有作用域。

每个作用域都是一个对象,包含该作用域内所有变量和函数的声明

2. 赋值操作

当执行赋值操作时,JavaScript会在作用域链逐级查找要赋值的变量。

3. 全局对象

全局对象是JavaScript中的一个特殊对象,它是所有作用域链的顶层对象。在浏览器环境中,全局对象是window对象

4. 创建全局属性

如果在所有作用域链中都找不到要赋值的变量,则JavaScript会在全局对象中创建一个新的属性并赋值。

所以注意:

访问一个没有声明的变量时,JS会报错;

给一个没有声明的变量赋值时,JS不会报错,会认为我们是要隐式声明一个全局变量。

5.显式声明与隐式声明

变量声明自带不可删除属性

1
2
3
var name = 'muzidigbig' 

name = 'muzidigbig'

前者是变量声明,因此无法被删除;后者为全局变量的一个属性,因此可以从全局变量中删除。

当使用var声明一个变量时,创建的这个属性是不可配置的,也就是说无法通过delete运算符删除。

函数体内变量回收机制

在函数执行后是否会被回收取决于变量是否被引用

如果变量在函数执行后 仍然被引用 ,那么 不会被回收

  • 情况一:返回变量给函数外部 (最好理解)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function foo() {
    var x = 1;
    return x;
    }

    var y = foo();
    //console.log(x)
    //>>Uncaught ReferenceError: x is not defined
    //无法在外部使用函数内局部变量
    console.log(y); // 1
    //可以引用返回的变量
  • 情况二:内部函数引用外部函数的局部变量(封装变量),内部函数在执行时,可以访问该变量。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    function foo() {
    var x = 1;

    function bar() {
    console.log(x); // 1
    }

    return bar;
    }

    var baz = foo();

    baz(); // 1
    //返回的内部函数bar,其引用了x变量,因此其未被销毁。
    //在执行时,可以访问

    //下面这是一个延迟执行的函数,内部嵌套的子函数引用了局部变量a,在延迟执行时,依旧可以访问该变量。
    function foo() {
    let a=1
    setTimeout(function() {
    alert(a);
    }, 1000);
    }
    foo();//打印输出1
  • 情况三:事件处理程序函数中的引用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var button = document.getElementById("button");
    // 在母元素中移除按钮元素,但此时仍有变量引用该button
    button.parentNode.removeChild(button);
    alert(button.innerHTML+"1")//打印出文字节点+1
    // 点击页面空白区域
    document.body.addEventListener("click", function() {
    alert(button.innerHTML+"2"); //在10s内点击body,打印出文字节点+2
    });
    setInterval(function(){
    button=null
    },10000)
    //10s后,引用的button变量的值被回收,此时点击会报错了。
    //因此仅在事件处理函数中引用,也会被回收

JS的undefined和null

JS的undefined和null

参考资料:

js 变量声明 (var使用与不使用的区别)