这是我参与「第四届青训营 」笔记创作活动的第13天。 本文总结了作用域与作用域链,解释了作用域链在js中是如何存在的。
作用域
执行环境中,变量或函数的作用范围。
定义了变量或函数有权访问的其他数据。
作用域都有一个变量对象。
全局作用域
- 全局作用域在页面打开时被创建,页面关闭时被销毁。
- 编写在script标签中的变量和函数,作用域为全局,在页面的任意位置可以访问到。
- 全局作用域可以认为是window,因为所有全局变量和函数都是作为window对象的属性和方法创建的。
局部作用域
- 函数调用时,函数作用域被创建,函数执行完毕,函数作用域被销毁。
- 每调用一次函数就会创建一个新的函数作用域,他们之间相互独立。
- 函数作用域可以访问上层作用域,但两个相邻函数间作用域相互独立。
es6之后的块级作用域
用let、const声明的变量,作用域在定义处的大括号内,对外不可见。 函数中的[[ Scopes ]]属性存放了它的作用域信息,Script是块级作用域,Global是全局作用域
作用域链
变量的取值首先会在创建这个变量的函数的作用域中取值,如果在当前作用域中没有找到,则会向上级作用域去查找,直到向上查找全局作用域,这个过程形成的链条就称为作用域链。
考核点
-
解释为什么打印函数对象时,Scope属性只能看到Global。 当函数执行时,Scope中有Global和Local,执行完毕后Local被销毁。
-
为什么闭包会导致内存泄漏 每一个作用域链都有变量对象,函数所包含的称为活动对象,每一个变量对象内都包含着对上一个对象的引用
var a=10;
function fun(){
var b=20;
return function fn(){
var c=30;
b=40;
}
}
const fn = fun();
console.dir(fun);
// [[Scopes]]: Scopes[2]
// 0: Script {fn: ƒ}
// 1: Global
console.dir(fn);
// [[Scopes]]: Scopes[3]
// 0: Closure (fun) {b: 20} //保存了上一层对象的变量。//若fn未引用b,则不会保存b。
// 1: Script {fn: ƒ}
// 2: Global
代码执行过程
在创建fn函数时,会创建一个预先包含全局变量对象的作用域链,这个作用域链被保存在内部的Scope属性中。当调用fn函数时,会为函数创建一个执行环境,然后通过复制函数的Scope属性中的对象构建起执行环境的作用域链,然后创建活动对象AO并推入执行环境的作用域链。在fn执行完成后,作用域就会被销毁。