一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第28天,点击查看活动详情。
前端开发的第三年,突然发现,对于JS,我还有很多不懂的地方,趁着最近需求少,不如静下心来,从头把JS再学一遍,查漏补缺。
本系列以廖雪峰的《JavaScript教程》和《现代 JavaScript 教程》两个电子书作为线索,对其中需要进一步了解的知识,会阅读更多的文章,并作为扩展知识记录下来。
新手建议先阅读上面两个电子书,本系列更适合用来复习旧知识和查漏补缺。
思维导图
通过下面的思维导图,我们先对JavaScript的函数作用域、闭包一些基本的了解。
函数作用域
作用域决定了变量的可访问性,全局作用域,局部作用域(函数作用域)。
let和const具有块作用域,块级作用域包括在函数内部和在一个代码块内部。
作用域链
表示不同作用域里面,有多个同名变量,变量的优先次序。
例如在下面的例子中,a变量的作用域链是:局部变量a(banana)->全局变量a(apple),优先取到局部变量。
let a = 'apple';
function say(){
let a = 'banana';
console.log(a); // banana
}
say();
*var的声明提升
用var声明变量,会把变量声明提升到所有代码之前,类似示例2.
// 示例1
var a = 'apple';
function say(){
console.log(a); // undefined
var a = 'banana';
console.log(a); // banana
}
say();
上面的示例1等同于示例2。
// 示例1
var a = 'apple';
function say(){
var a;
console.log(a); // undefined
a = 'banana';
console.log(a); // banana
}
say();
闭包
一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在 JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
词法环境
**词法环境(Lexical Environment)**是作用域内部(隐藏)的关联对象。
词法环境对象由两部分组成:
- 环境记录(Environment Record) —— 一个存储所有局部变量作为其属性(包括一些其他信息,例如
this
的值)的对象。 - 对 外部词法环境 的引用,与外部代码相关联。
函数的执行,可以分为创建词法环境的阶段和执行的阶段。
创建阶段
创建作用域链、变量对象、决定this。
执行阶段
变量赋值、函数引用等。
看下面这个例子
let name = 'apple'
function say(){
let name = 'banana';
console.log(name);
}
内部的语法环境,有name这个变量,外部的语法环境也有name这个变量。
代码访问变量时,先搜索内部的语法环境,如果逐层搜索外层的外部环境。