作用域与闭包(精简)

1,931 阅读2分钟

「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。

对作用域的简单了解。

在JS中,对数据进行读写操作的空间就是作用域。比较常见的就是变量的作用域,那么变量的作用域就是我们比较熟悉的包括全局作用域以及局部作用域。

  • 全局作用域: 全局作用域定义的变量是不会被回收的,函数内部的作用域是可以 访问函数外部的变量的。

  • 局部作用域:JS是没有块级作用域的,所以我们是用函数作用域来模拟块级作用域。

函数的环境和作用域的原理


首先,定义一个函数,每次调用都会开辟一个新的内存空间,内存空间里面定义的变量函数外面是不可以访问的。当每次开辟空间时,没有被使用的变量以及方法就会被清除掉,当数据有被使用的机会的时候,环境就会被保留。

function jxx() {
    let n = 1;
    function sum() {
        console.info(++n);
    }
    sum();
}
jxx(); // 此时的结果就是无论调用多少次输出的都是2
// 原因如下:
// 当每次调用jxx()时都会开辟一块新的内存空间,而内存空间中的sum也会开辟一块新的内存空间
// 所以 无论调用多少次 都不会进行累加

如果想要实现累加,那么就需要这个函数不被清除掉。下面说一下这个方法的两种实现方式

延申函数环境生命周期


  • 第一种方式
function hd() {
    let n = 1;
    return function() {
        let m = 1;
        console.info(++n);
        return function() {
            console.info(++m);
        };
    };
}
let a = hd()();
a();
a();
// 此处会出现累加,原因是因为我们将所需要的累加方法正在被使用,不会被清除掉

构造函数中作用域的使用形态


// 以下这种形态也会累加,原理同上
 function Jxx() {
    let n = 1;
    this.sum = function() {
        console.info(++n);
    };
}
let a = new Jxx();
a.sum();
a.sum();

闭包


一句话概括就是子函数可以访问其他函数作用域当中的数据。

下面简单介绍一下我平时利用闭包实现的一些常见功能。

  • 利用闭包特性获取某一区间内的值
   let arr = [1,2,35,6,7,8,87,36];
   function between(a,b) {
       return function(v) {
           return v >= a && v <= b;
       }
   }
   console.info(arr.filter(between(3,9)));
  • 利用闭包进行数据字段的排序
    lessons = [
        {price: 12, click: 19},
        {price: 13, click: 88},
        {price: 49, click: 59},
        {price: 14, click: 58},
     ]

     function order(field) {
         return function(a, b) {
             return a[field] > b[field] ? 1 : -1; // 大于0升序,小于0降序
         }
     }
     let jxx = lessons.sort(order('click'));
     console.table(jxx);
  • 闭包内存泄漏的解决方法
    在合适的位置将数据设置为空
  • this在闭包中的历史遗留问题
    使用箭头函数正确的找到this