美文网首页
浅谈闭包

浅谈闭包

作者: 萌萌加油站 | 来源:发表于2019-05-08 21:49 被阅读0次

    闭包是JavaScript的重点也是难点之一,由于涉及多重知识点,对初学者来说比较难理解。本文将闭包相关的知识点进行梳理,帮助大家更好的理解闭包。下面从4个部分进行说明:即作用域、执行上下文、闭包和内存管理。

    文章重点内容如图所示:

    image.png

    1、作用域

    作用域其实就是定义了一套规则用来查找变量,控制着变量与函数的可见性和生命周期。在JavaScript中,有全局作用域和函数作用域,随着es6的发展,引入了块级作用域。

    • 全局作用域

    在代码中任何地方都能访问到的对象拥有全局作用域,一般来说以下几种情形拥有全局作用域:

    (1)最外层函数和在最外层函数外面定义的变量拥有全局作用域

    (2)所有末定义直接赋值的变量自动声明为拥有全局作用域

    (3)所有window对象的属性拥有全局作用域

    • 函数作用域

    在函数内声明的变量,在当前函数可访问。

    • 块级作用域

    Es6增加了let和const声明变量,也使得作用域更加丰富,增加了块级作用域。

    总结:在JavaScript执行函数时,遇到变量,先按照“就近”原则在函数内部找该变量的声明或者赋值。若没有找到,则继续向上个函数作用域查找,直到最顶层作用域。整个查找过程层层递进,形成一个链就是作用域链。

    2、执行上下文和调用栈

    • 执行上下文

    执行上下文是当前代码的执行环境/作用域。每个执行环境都有一个与之关联的变量对象(VO),执行环境中定义的所有变量和函数都会保存在这个对象中,解析器在处理数据时就会访问这个内部对象。

    JavaScript执行主要分为两个阶段:代码预编译和代码执行阶段。

    代码预编译是编译器将JavaScript代码编译成可执行的代码,同时对变量的内存空间进行分配(变量提升过程再此阶段完成),作用域也在该阶段确定。

    执行阶段主要任务是执行代码,执行上下文在这个阶段全部创建完成。包括:变量对象、作用域链及this的指向

    • 调用栈

    在执行一个函数时,如果这个函数又调用了另外一个函数,而这个“另外一个函数”也调用了“另外一个函数”,便形成了一系列的调用栈。

    3、闭包

    • 什么是闭包?

    比较容易理解的版本定义如下:

    函数嵌套函数时,内层函数引用了外层函数作用域下的变量,并且内层函数在全局环境下可访问,就形成了闭包

    • 为什么会有闭包

    由于JavaScript的作用域只能向上层函数访问,内部函数的变量外部函数无法访问(执行完上下文被销毁),为了解决这个问题,出现了闭包。这样外界可以通过这个返回的函数获取原函数内部的变量值。

    • 闭包有哪些优点

    简单来说闭包为访问函数内部变量提供了途径和便利。这样可以实现“模块化”

    • 闭包的缺点

    由于闭包使得变量常驻内存,滥用闭包会导致内存的大量消耗,导致内存泄漏问题。

    4、内存管理

    • 基本概念

    内存管理都是指对内存生命周期的管理,包括分配内存空间、读写内存和释放内存空间。

    • 内存空间分为:

    栈空间:由操作系统自动分配释放,存放函数的参数值,局部变量的值等

    堆空间:一般由开发者分配释放,要考虑垃圾回收的问题

    一般情况下基本数据类型存放在栈内存中,引用类型保存在堆内存当中

    • 内存泄漏

    内存泄漏是指内存空间明明已经不再被使用,但由于某种原因并没有被释放的现象

    • 浏览器垃圾回收

    两种算法实现主动垃圾回收:标记清楚法和引用计数法

    垃圾回收优质文章参考:

    1. 通过垃圾回收机制理解 JavaScript 内存管理

    2. 如何处理 JavaScript 内存泄漏

    3. 垃圾回收

    4. 编写内存友好的代码

    5. JavaScript 中 4 种常见的内存泄漏陷阱

    6. 记一次网页内存溢出分析及解决实践

    本文讲解了闭包相关的基本知识,有了这些知识再通过实例练习,相信聪明的你一定可以掌握闭包了。

    相关文章

      网友评论

          本文标题:浅谈闭包

          本文链接:https://www.haomeiwen.com/subject/nxdboqtx.html