作用域、作用域链、执行上下文、预编译
2019-04-11 本文已影响7人
李轻舟
1、作用域
作用域是在运行时代码中的特定变量的有效范围。作用域决定了代码区块中变量和其他资源的可见性。作用域内层可以看见作用域外层,作用域外层不能看见作用域外层,所以作用域在不同作用域中声明的变量不会造成污染和命名冲突。
- 全局作用域
定义在最外层的函数和变量,未经声明就赋值的变量,window的属性。这里需要注意的是var声明的全局变量以及未经声明就赋值的变量会挂载到window属性上,但是var声明的变量不能删除,未经声明的变量可以删除。
- 函数作用域
当函数执行的时候就会在内部创建一个函数作用域,当函数执行完成就会销毁该作用域。
- 块级作用域
在ES6之前是没有块级作用域的,ES6引入了let、const关键字就可以创建块级作用域。
2、作用域链
当在一个函数内部搜索一个变量的时候,如果该函数没有声明该变量,那么就会顺着代码执行环境创建的作用域逐层向外搜索,一直搜索到全局作用域。
3、执行上下文
解释阶段:
- 词法分析
- 语法分析
- 作用域规则确定()
执行阶段:
- 创建执行上下文
- 执行函数代码
- 垃圾回收
JavaScript在解释阶段便会确定作用域规则,但是执行上下文是在函数执行的前一刻。
执行上下文最明显的就是this指向是在执行的时候确定的。
区别:执行上下文在运行时确定,随时可以改变;作用域在定义时就确定,并且不会改变。同一作用域下,不同的调用会产生不同的执行上下文,从而产生不同的结果。
4、预编译
- 创建AO对象
- 寻找形参和变量声明
- 形参实参相统一
- 找函数声明,函数名作为属性名,函数体作为属性值
5、闭包
当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域外执行。简单讲,闭包就是指有权访问另一个函数作用域中的变量的函数。
创建闭包:
- 在函数内部引用外部函数
let a = 1
function foo() {
console.log(a)
}
function bar() {
let a = 2
foo()
}
bar() // 1
在函数内部返回函数
let a = 'window'
function foo() {
let a = 'foo'
return function() {
console.log(a)
}
}
let bar = foo()
bar() // foo
闭包的应用和缺陷
- 设计私有的方法和变量。
- 容易造成内存泄露。