闭包是一种现象,是指一个函数能够引用其他函数的变量和函数。而之所以会产生这种现象,原因是作用域链的存在。代码进行自己的执行上下文,执行上下文中存储着作用域链的地址。在对变量进行解析的时候,如果在自己的活动对象中找不到,就会循着作用域链去外部函数的活动对象上寻找,这样就能够在此函数中访问外部函数的变量了。
闭包
概念
闭包是指,一个函数可以访问另一个函数作用域中的变量
一般创建闭包的方式是,在一个函数的内部创建一个新的函数。
这个内层函数可以访问外层函数的作用域,可以访问这个外层函数作用域中的变量
特性
如果一个函数的变量和函数被其他的函数引用,那么它不能再他自己执行完之后立即销毁,需要等待引用它变量和函数的函数执行完才会销毁
作用
定义一个函数,就会形成一个函数作用域。在这个函数作用域中声明的变量,只能在这个函数中使用,并且,函数执行完之后,这个函数中的变量所占的空间就会被收回。那么,如果我们希望在一个函数执行完之后,还是可以用它的变量呢?闭包可以实现这个需求。
缺点
根据上面闭包的特性可以看出来,闭包是消耗内存的
执行上下文
概念
每段代码的执行都会在一个执行上下文中,变量或函数的的执行上下文决定他们能访问哪些数据,以及他们的行为。每个执行上下文关联一个变量对象,在这个上下文中定义的所有变量和函数都在这个对象上。
程序的执行流就是通过执行上下文控制的。
运作流程
每个函数都有自己的上下文,代码执行流进入函数,函数的上下文会被推到上下文栈,函数执行完毕后,该函数的上下文会从执行上下文栈中弹出
作用域/作用域链
作用域链
代码在上下文中执行时,会为变量对象创建一个作用域链,这个作用域链决定此上下文代码访问变量和函数的顺序
作用域
什么是作用域?
作用域是一个范围,是变量定义和调用的范围。在不同的地方定义变量,就能在相应的不同地方调用变量。
比如JavaScript中有全局作用域、函数作用域、块级作用域。
- 变量定义在全局环境,任何位置都可以访问到这个变量
- 变量定义在函数内部,就只能在这个函数内部访问变量。变量定义在代码块中,就只能在这个函代码块中访问这个变量
其中,在函数作用域中,涉及变量提升的问题。
变量提升
变量提升是指在函数内部,变量的声明被提升到函数顶部位置,但是变量的赋值不会被提升
只有用var声明的变量才会变量提升
函数提升
函数提升是指函数声明在调用之后
变量提升时,只提升声明,不提升赋值。
而函数提升时,里面的逻辑也被提升。
函数定义主要用两种方式:
- 函数声明 function后面直接加名字
function foo() {}
- 函数表达式 用var const 变量赋值
var fun = function () {}
其中,函数声明,会被函数提升。函数表达式,不会被函数提升。