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

61 阅读3分钟

闭包是一种现象,是指一个函数能够引用其他函数的变量和函数。而之所以会产生这种现象,原因是作用域链的存在。代码进行自己的执行上下文,执行上下文中存储着作用域链的地址。在对变量进行解析的时候,如果在自己的活动对象中找不到,就会循着作用域链去外部函数的活动对象上寻找,这样就能够在此函数中访问外部函数的变量了。

闭包

概念

闭包是指,一个函数可以访问另一个函数作用域中的变量

一般创建闭包的方式是,在一个函数的内部创建一个新的函数。

这个内层函数可以访问外层函数的作用域,可以访问这个外层函数作用域中的变量

特性

如果一个函数的变量和函数被其他的函数引用,那么它不能再他自己执行完之后立即销毁,需要等待引用它变量和函数的函数执行完才会销毁

作用

定义一个函数,就会形成一个函数作用域。在这个函数作用域中声明的变量,只能在这个函数中使用,并且,函数执行完之后,这个函数中的变量所占的空间就会被收回。那么,如果我们希望在一个函数执行完之后,还是可以用它的变量呢?闭包可以实现这个需求。

缺点

根据上面闭包的特性可以看出来,闭包是消耗内存的

执行上下文

概念

每段代码的执行都会在一个执行上下文中,变量或函数的的执行上下文决定他们能访问哪些数据,以及他们的行为。每个执行上下文关联一个变量对象,在这个上下文中定义的所有变量和函数都在这个对象上。

程序的执行流就是通过执行上下文控制的。

运作流程

每个函数都有自己的上下文,代码执行流进入函数,函数的上下文会被推到上下文栈,函数执行完毕后,该函数的上下文会从执行上下文栈中弹出

作用域/作用域链

作用域链

代码在上下文中执行时,会为变量对象创建一个作用域链,这个作用域链决定此上下文代码访问变量和函数的顺序

作用域

什么是作用域?
作用域是一个范围,是变量定义和调用的范围。在不同的地方定义变量,就能在相应的不同地方调用变量。

比如JavaScript中有全局作用域、函数作用域、块级作用域。

  • 变量定义在全局环境,任何位置都可以访问到这个变量
  • 变量定义在函数内部,就只能在这个函数内部访问变量。变量定义在代码块中,就只能在这个函代码块中访问这个变量

其中,在函数作用域中,涉及变量提升的问题。

变量提升

变量提升是指在函数内部,变量的声明被提升到函数顶部位置,但是变量的赋值不会被提升

只有用var声明的变量才会变量提升

函数提升

函数提升是指函数声明在调用之后

变量提升时,只提升声明,不提升赋值。

而函数提升时,里面的逻辑也被提升。

函数定义主要用两种方式:

  • 函数声明 function后面直接加名字
function foo() {}
  • 函数表达式 用var const 变量赋值
var fun = function () {}

其中,函数声明,会被函数提升。函数表达式,不会被函数提升。