基本知识
作用域
作用域其实就是一套规则:这个规则 用于确定在特定场景下如何查找变量 。
函数作用域和全局作用域
总结一下 :在 JavaScript 执行一段函数时,遇见变量读取其值,这时候会“就近”先在函数内部找该变量的声明或者赋值情况。这里涉及“变量声明方式”以及“变量提升”的知识点。
块级作用域和暂时性死区
function foo(arg1 = arg2, arg2) {
console.log(`${arg1} ${arg2}`)
}
foo(undefined, 'arg2')
// Uncaught ReferenceError: arg2 is not defined
foo(null, 'arg2')
因为除了块级作用域以外,函数参数默认值也会受到 TDZ 影响。
function foo(arg1) {
let arg1
}
foo('arg1')
实际上会报错:Uncaught SyntaxError: Identifier ‘arg1’ has already been declared。这同样跟 TDZ 没有关系,而是因为函数参数名会出现在其“执行上下文/作用域”当中。
执行上下文和调用栈
执行上下文
代码执行的两个阶段
- 代码预编译阶段
- 代码执行阶段
结论 作用域在预编译阶段确定,但是作用域链是在执行上下文的创建阶段完全生成的。因为函数在调用时,才会开始创建对应的执行上下文。执行上下文包括了:变量对象、作用域链以及 this 的指向
调用栈
闭包
我们知道正常情况下外界是无法访问函数内部变量的,函数执行完之后,上下文即被销毁。但是在(外层)函数中,如果我们返回了另一个函数,且这个返回的函数使用了(外层)函数内的变量,外界因而便能够通过这个返回的函数获取原(外层)函数内部的变量值。这就是闭包的 基本原理