JavaScript进阶:作用域、作用域链、闭包

要想弄清楚变量、函数等的生命周期就要先弄清楚作用域。要理解变量提升也要先弄明白作用域。今天看了作用域、作用域链、闭包方面的内容,整理出来,加深记忆。

1.作用域

  1. 什么是作用域?

    作用域是可以访问变量、对象、函数的集合,指一个变量的作用范围。它相对于上下文对象是静态的, 在编写代码时就确定了。
    作用域非常重要,它控制着变量与参数的可见性与生命周期。

  2. 作用域的作用是什么?

    隔离变量,不同作用域下同名变量不会有冲突。

  3. 作用域的分类呢?

    a.全局作用域

    • 变量在函数外定义,就是全局变量。

    • 全局作用域中的变量都是全局变量,在页面的任意的部分都可以访问到。

    • 全局变量有全局作用域,直接编写在script标签中的JS代码,也都在全局作用域。

    • 在全局作用域中有一个由浏览器创建的全局对象window,它代表的是浏览器的窗口,我们可以直接使用。

    • 在全局作用域中创建的变量都会作为window对象的属性保存。
      如下:
      JavaScript进阶:作用域、作用域链、闭包_第1张图片
      输出结果为:
      在这里插入图片描述

    • 在全局作用域中创建的函数都会作为window对象的方法保存。
      如下:
      JavaScript进阶:作用域、作用域链、闭包_第2张图片

      如果变量在函数内没有声明(没有使用 var 关键字),该变量为全局变量。
      如下:
      JavaScript进阶:作用域、作用域链、闭包_第3张图片

    b.局部(函数)作用域

    • 变量在函数内声明,该变量为局部作用域,也称为函数作用域。

    • 局部变量:只能在函数内使用。所以不同的函数可以使用相同的变量名称。
      如下:
      JavaScript进阶:作用域、作用域链、闭包_第4张图片

    • 局部变量在函数开始执行时创建,执行结束后自动销毁。

      函数参数:函数参数只在函数内起作用,是局部变量。

    c.块级作用域(ES6新增)

    • javascript中没有块级作用域的概念。ES6中新增加块级作用域。
      什么是没有块级作用域?如下:
      JavaScript进阶:作用域、作用域链、闭包_第5张图片
    • 大括号{}中间的部分都是块级作用域。{}之中定义的所有变量在代码块外都是不可见的,所以称之为块级作用域。
    • let定义的变量和const定义的常量都是块级作用域。
      详细参考 块级作用域及let和const的特点及其区别
  4. JavaScript 变量生命周期

    • 变量生命周期在它被声明时初始化。
    • 局部变量在函数执行完毕后销毁。
    • 全局变量在页面关闭后销毁。
    • 函数的参数也是局部性的,只在函数内部起作用。

2.作用域链

  1. 什么是作用域链:

    • 作用域链(Scope Chain)是javascript内部中一种变量、函数查找机制,它决定了变量和函数的作用范围,即作用域。
    • 查找变量时就是沿着作用域链来查找的。
    • 当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有就直接使用(就近原则)。如果没有则向上一级作用域中寻找,直到找到全局作用域;如果全局作用域中依然没有找到,则会报ReferenceError。
    • 外部函数定义的变量可以被内部函数所使用,内部定义的则不可被外部使用。
      【注意】
      1.函数内部的作用域可以访问函数外部的作用域
      2.如果有多个函数嵌套,那么就会构成一个链式访问结构,这就是作用域链。
      如下:
      JavaScript进阶:作用域、作用域链、闭包_第6张图片

    变量查找规则如下:
    JavaScript进阶:作用域、作用域链、闭包_第7张图片

3.闭包

  1. 什么是闭包?如何产生闭包?闭包的影响?注意点?
    1.闭包

    • 私有变量会用到闭包。
    • 有权访问另一个函数作用域内变量的函数都是闭包。
    • 闭包就是能够读取其他函数内部数据(变量/函数)的函数。

    2.闭包产生条件

    • 函数嵌套,嵌套的内部(子)函数引用嵌套的外部(父)函数的变量或函数,产生闭包,内部函数不引用外部函数的变量时不会差生。
    • 一个函数作为另一个函数的返回值。
    • 外部函数的实参传递给另一个函数调用。

    条件1示例如下:
    JavaScript进阶:作用域、作用域链、闭包_第8张图片
    内部plus函数访问了构造函数testcounter里面的变量i,于是就形成了闭包。下方是同样的道理。
    JavaScript进阶:作用域、作用域链、闭包_第9张图片
    条件2示例如下:
    JavaScript进阶:作用域、作用域链、闭包_第10张图片
    闭包是可访问上一层函数作用域里变量的函数,即便上一层函数已经关闭。
    条件3示例如下:
    JavaScript进阶:作用域、作用域链、闭包_第11张图片

    3.闭包的理解。

    1. 闭包是嵌套的内部函数(大部分人都知道)。
    2. 包含被引用变量 或者函数的对象。

    4.闭包的作用

    1. 使用函数内部的变量在函数执行完后, 仍然存活在内存中(延长了局部变量的生命周期。
    2. 让函数外部可以操作(读写)到函数内部的数据(变量/函数)。
    3. 在函数外部不能直接访问函数内部的局部变量,通过闭包让外部操作它。

    5.闭包的生命周期

    • 产生: 嵌套内部函数被声明时就产生了(不是在调用时)。
    • 死亡: 嵌套的内部函数成为垃圾对象时死亡。(比如f = null,就可以让f成为垃圾对象。意思是,此时f不再引用闭包这个对象了)。

    6.闭包的应用

    • 定义具有特定功能的js模块。
    • 将所有的数据和功能都封装在一个函数内部(私有的),只向外暴露一个包含n个方法的对象或函数。
    • 模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能。

    7.闭包的注意点
    问题1:
    由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。
    解决方法:
    在退出函数之前,将不使用的局部变量全部删除。

每天进步一点点,开心一点点,快乐一点点!come on!

你可能感兴趣的:(JavaScript)