js作用域、执行上下文、闭包

56 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

变量的作用域

  • 全局作用域:全局变量:函数外创建的变量,当前程序任意位置都可以使用
  • 局部作用域:局部变量:函数内创建的变量,只在当前函数内生效
  • 块级作用域(es6中的):const和let。只在块级作用域内可以使用

作用域和作用域链

  • 作用域:指的是一个变量的作用范围。一个变量如果是在全局环境下定义的,那么这个变量就存在于全局作用域下,在函数内部定义的变量,则存在于函数作用域下。
  • 作用域链:当一个代码在一个环境中执行时,会创建变量对象的一个作用域链,由子级作用域返回父级作用域中寻找变量,就叫做作用域链。作用域链的用途是保证对执行上下文有权访问的所有变量和函数的有序访问。作用域链的前端始终都是当前执行的代码所在的上下文的变量对象。 而js的函数在声明时,采用的是词法作用域,即在声明时就确定好了作用域,作用域的定义是静态的,也就是最开始创建时所在的环境,如果创建时所在的环境是全局环境,那么作用域链指的就是全局环境。

执行上下文

执行上下文:分为全局执行上下文和函数执行上下文,函数执行前的准备工作,也称为上下文环境。
执行上下文是执行函数前的准备工作,进入到一个环境时就创建一个执行上下文,根据环境的不同执行的上下文也不同。环境有三种,主要的是全局环境、函数环境。首先当执行js文件时进行的是全局环境执行全局上下文,当遇到函数时执行函数上下文。全局执行上下文只有一个在执行栈的栈底,函数执行上下文按照顺序以此在执行栈里排列,只有栈顶的函数执行上下文执行完毕退出执行栈,下面的执行上下文才能执行,全局上下文在站定等页面关闭或整个程序完成后才能出栈,因为执行栈遵循“先进后出”的规则。局部变量调不到的原因基本上是与它的执行销毁和作用域链有关

闭包

闭包的概念:是指有权访问另一个函数作用域中的变量的函数。
创建闭包的常见方式:在一个函数内部创建另一个内部(私有)函数。

image.png

闭包的应用

立即执行函数(function(){}()),可解决全局变量滥用的问题,利用回调函数,封装ajax,读取后台数据、以及防抖和节流等

闭包的注意事项

由于闭包会使得函数中的变量都保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,可能导致内存泄漏。解决办法是,在退出函数之前,将不能使用的局部变量全部删除,赋值为null(相当于出栈)
闭包会在父函数外部,改变父函数内部变量的值。所以,如果把父函数当做对象使用,把闭包当做它的公用方法,把内部变量当做它的私有变量,这时一定要小心,不能随便改变父函数的内部变量的值。

内存泄漏和内存溢出

  • 内存泄漏:是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏可以忽略,但内存泄漏堆积后果很严重,无论多少内存,迟早会被占光。
  • 内存溢出:是指程序在申请内存时,没有足够的空间供其使用。
内存泄漏的4种情况
  • 意外的全局变量(定义变量时没有加关键声明,尤其在函数中)
  • 被遗忘的计时器或回调函数
  • 脱离DOM的引用(把DOM存在变量里,然后调用这个变量,这个过程就是脱离DOM)
  • 闭包