闭包

166 阅读6分钟

闭包

概述

闭包就是函数嵌套函数,内部函数拥有外部函数的引用,导致这个引用就无法被GC回收

作用域(上下文对象)

全局作用域

在全局作用域内声明的函数或者变量都归属于当前的全局对象(global对象)

局部作用域(函数作用域)

在函数作用域内声明的变量或者形参都是归属于当前的上下文对象(context 对象)

函数的执行流程

  1. 预编译
  2. 调用执行(通过栈地址找到对应的函数 执行上下文)
  3. 执行完销毁当前的执行上下文对象

预编译

全局变量的预编译
  1. 创建对应的全局GO对象(global object)
  2. 将形参和变量都当作全局GO的属性 形参和变量赋值 指定默认值为undefined
  3. 形参和实参同步
  4. 找到函数声明 将对应的值给到函数体
局部变量的预编译
  1. 创建对应的局部AO对象(Activation object执行上下文对象)
  2. 将形参和变量都当作局部AO的属性 形参和变量赋值 指定默认值为undefined
  3. 形参和实参同步
  4. 找到函数声明 将对应的值给到函数体

GC(垃圾回收器)

主要回收机制
  1. 标签清除法(通过标记的形式来进行回收 如果当前这个内容没有被使用到 就会被回收)
  2. 引用计数 (通过不断计数操作来进行回收 有人用就+1 没人用就-1 到0的时候就会被回收)
闭包的特点

保持引用,数据进行缓存,不被垃圾回收机制回收

用途
  1. 作为缓存(缓存数据量小,加速快)
  2. 节流
  3. 防抖
  4. 函数柯里化
闭包的优缺点

优点:

  1. 保持了引用,内存不需要重新创建 加载速度快
  2. 扩大了函数内参数和变量的作用范围
  3. 利用内部函数来访问外部函数的参数或者变量,避免了数据污染

缺点:

  1. 内存占用大(一直保持引用),滥用容易造成内存泄露。
  2. 通过返回函数的形式进行调用,需要不断开辟函数空间  容易内存溢出

防抖

在规定时间内只执行一次,执行的是最后一次(防止高频触发  在高频触发的时候只执行一次)

节流(thorttle)

在限定时间内只执行一次,执行第一次(减少触发次数)

函数柯里化(currying)

将多参数的函数分解成单一参数的函数,主要是可以延迟传入参数(bind也是一个柯里化函数

函数柯里化的优点
  1. 延迟传入参数
  2. 参数复用
参数柯里化的核心

参数个数没到,返回函数,参数个数到了返回结果

反柯里化

将一个原本对象没有的方法进行调用(利用的this指向更改)

Promise

概述

promise 是es6新增的一个类,主要用于处理异步问题(异步代码同步执行)主要解决了回调地狱的问题,他翻译为承诺,主要有三种状态,第一种为成功状态(fulfilled),第二种为失败状态(rejected),第三种为等待状态(pending)(默认状态) promise类的实例化

promise 的相关原型方法(背.重要)
  1. then 处理成功的方法
  2. catch 处理失败的方法
  3. finally 处理状态更改的方法
promise的静态方法
  1. all 同步并行执行所有的promise 当有一个错误就返回错误的那个promise的结果 当成功就返回所有的结果
  2. race 竞速 返回最先执行完的promise结果
  3. rejected 返回一个失败状态下的promise
  4. resolve 返回一个成功状态下的promise
  5. allselted 同步并非行执行所有的promise 不管成功失败都返回所有的结果 且状态为成功

总结

  1. promise 的所有的方法返回的都是一个新的promise对象
  2. then方法允许传入两个参数(参数类型为函数)他的第一个函数接收resolve的处理 它的第二个函数参数接收reject的处理
  3. catch接受对应的reject的处理,抛出错误它可以接收(接受错误状态会更改为(rejected)
  4. then和catch都会发生值穿透问题(传入参数非函数就会发生值穿透)
  5. then和catch中如果return数据那么就会将数据传递给下一个then 如果抛出错误就会将数据传递给下一个catch
  6. finally处理状态更改的方法(只要状态发生变化它就会被调用)

回调地狱

回调函数的无限嵌套 造成了回调地狱

  1. 回调地狱主要是代码的可读性低
  2. 可维护性低,造成代码没有存在的价值
利用promise来解决回调地狱
  1. 利用then方法返回的是一个promise 的特性(无限调用then方法)
  2. 利用then方法中调用return 可以进入下一个then的特性
核心实现

在对应的then方法中调用return。返回一个新的promise来解决回调地狱的问题

ES7新增的async awiat

  1. async awiat 是一种语法糖
  2. async 是用于修饰函数的(async修饰的函数返回一个新的promise)
  3. awiat 是用于修饰promise的(只能在async修饰的函数内使用)
eventLoop(事件轮询)

JavaScript是单线程(js引擎只有一个),同步先执行异步后执行

异步执行机制

异步代码执行机制其实就由webApi进行任务队列(先进先出)的分发

任务队列的组成又分为宏任务队列和微任务队列
  1. 宏任务队列(属于基础的异步代码JavaScript、事件执行、定时器、延时器...)
  2. 微任务队列(属于宏任务里面的promise就是微任务)
任务队列的执行机制被称为事件轮询

注意事项

  1. 先宏后微
  2. 先进入JavaScript的宏任务,然后推入里面的同步代码,再去找对应的微任务队列
  3. 将对应的微任务队列的内容按照加入队列的顺序进行推入执行栈(加载顺序),执行完对应所有的微任务开启下一个宏任务
  4. 如果当前宏任务是setTimeout或者是setInterval那么这个执行的机制取决于间隔的时间(间隔时间一直取决于加载顺序)
  5. 将当前的宏任务,里面的同步代码推入执行栈 再找到对应的微任务队列执行微任务...不断重复直到微任务队列及宏任务队列都清空