第十八章 函数的高级应用 - 闭包函数

文章目录

  • 一、闭包函数
      • 1. 函数定义阶段
      • 2. 函数调用阶段
      • 3. 不会销毁的函数执行空间
      • 4. 闭包
  • 二、函数防抖
  • 三、函数节流
  • 四、函数的柯里化(Currying)
  • 五、课外阅读

一、闭包函数

1. 函数定义阶段

  1. 在堆内存中开辟一段存储空间
  2. 把函数体内的代码存储在这一段空间内
  3. 把堆空间地址赋值给栈内存中的变量

2. 函数调用阶段

  1. 按照变量名内的空间地址找到堆内存中对应的存储空间
  2. 在调用栈中开辟一段新的作用域执行空间
  3. 在执行空间中进行形参赋值
  4. 在执行空间中进行预解析(声明提升,检查报错等)
  5. 在执行空间中完整执行一遍函数内的代码
  6. 将当前作用域执行空间,销毁

3. 不会销毁的函数执行空间

  1. 当函数内返回了一个复杂数据类型
  2. 并且函数外部有变量接收了这个复杂数据类型
  3. 函数执行完毕后的执行空间不会被销毁
function fn() {
  const obj = { name: 'admin' }
  return obj
}

const res = fn();
console.log(res);		// { name: 'admin' }

// 如果需要释放这个空间,给 res 重定向, 即可
res = null;

4. 闭包

  1. 概念:通过作用域的嵌套,将原本的局部变量(原本要删除的数据)进化成私有变量的过程,叫闭包
    • 原理:利用了不会被销毁的执行空间,保存原本要删除的数据
  2. 创建一个不会被销毁的作用域执行空间
  3. 直接 或 间接 返回一个函数(复杂数据)
  4. 外部有变量接收的返回的复杂数据
  5. 返回的这个函数使用了外部函数的局部变量(私有变量)
function fn(){
  let a = 10;
  return function(){
    return a;
  }
}
let res = fn();
console.log( res() );  // 10
  1. 特点
    • 可以在函数外面控制到函数内部的变量
    • 避免全局变量命名空间的污染
    • 延长了变量的生命周期(多占用内存)
    • 因为存在不会销毁的空间,低版本浏览器会造成内存溢出
  2. 沙箱模式
function outer() {
  let a = 10;
  let str = 'hello world';

  // 返回一个对象
  return {
    // 对每个私有变量都准备两个函数:get用来获取,set用来修改
    getA () { return a },
    setA (val) { a = val },
    getStr (val) { return a },
    setStr: function (val) { a = val }
  }
}

二、函数防抖

  1. 函数防抖:
    • 短时间内快速触发同一个事件
    • 执行之前都先干掉上一次,保证只执行最后一次
  2. 特点:
    • 提升执行速度,节省资源
  3. 使用setTimeout实现函数防抖
var t = null;
document.onmousemove = function (){
  clearTimeout(t);
  t = setTimeout(() => {
      console.log("函数防抖:多次触发只会执行一次");
  }, 300);
}
  1. 应用场景 - 一些高频事件,在被连续触发时,其实只需要生效一次即可,如:
    • 搜索框搜索输入:只需用户最后一次输入完,再发送请求
    • 以此可以延伸出手机号、邮箱等输入时的实时验证
    • 窗口大小事件onresize,只需窗口调整完成后,计算窗口大小,防止重复渲染

三、函数节流

  1. 函数节流:
    • 短时间内快速触发同一个事件
    • 上次执行未结束,不能再次触发,一次执行完毕后,才能触发下一次
  2. 特点:
    • 提升执行速度,节省资源
  3. 使用 状态的概念 实现函数节流
var t = null;
document.onmousemove = function (){
    if(t) return;
    t = setTimeout(() => {
        console.log("函数节流");
        t = null;
    }, 300);
}
  1. 应用场景
    • DOM 元素的拖拽(mousemove)
    • 射击游戏在单位时间只能发射一颗子弹(mousedown/keydown)
    • 搜索联想(keyup)
    • 懒加载,在滚动过程中判断是否需要加载图片(scroll)

四、函数的柯里化(Currying)

  • 是一种函数的高阶技术,用于函数的转换,并不会执行函数。可将一次传入多个参数的函数,转换为多次执行一次执行传入一个参数的函数
    • 如:fn(1,2,3)转换为fn(1)(2)(3)
    • 利用了闭包, 把第一次传递的参数保存下来(延长生命周期)
    • 也可以保存程序的逐步执行结果
function fn(a, b){
  return a + b
}
// 转为
function fn(a) {
  return function (b) {
    return a + b
  }
}

五、课外阅读

js的垃圾回收机制
函数节流
函数防抖

你可能感兴趣的:(从零开始学JavaScript,前端,javascript,闭包函数,函数防抖,函数节流,柯里化,function)