通过在js文件增加debugger;查看运行期 Scope变化,来理解变量的查找规则;
执行前 scope
- 可以 理解为堆栈,隐藏查找规则;
- 脚本块包括 Global和Script 两个;
- 变量查询是从上到下,即可Script,再Global;
- 在执行前,存在的变量名是编译阶段处理,返回声明对象集合;
执行后
- 变量赋值了
a_global_fun 函数执行
- 当前函数声明 存储在 Local类型,压入栈;
- Local中变量包括函数形参、变量、this;
- 站在a_global_fun函数内,查找变量的属性是依次查找 Local、Script、Global ,找不到则抛出
ReferenceError;
fun_level_1 函数执行
- 当前函数声明 存储在 Local类型,压入栈;
- Local栈之前栈,由于当前函数引用了外部函数的声明,形成闭包,因此类型标记为 Closure类型;
- Script和Global依次不变;
fun_level_2 函数执行
- 此时堆栈长度是5, Local、Closure(fun_level_1)、Closure(a_global_fun)、Script、Global;
- 变量查询从栈顶到站底;
通过观察 chrome 控制台,scope 的变化,理解变量的声明、赋值、查找规则;
栈模型即是运行时的上下文,决定变量的查找规则;
"use strict";
// (1): 执行前
debugger;
var a_global_var = "a_global_var";
let a_srcipt_let = "a_srcipt_let";
const a_srcipt_const = "a_srcipt_const";
this["a_global_obj"] = { a: { b: { c: "a_global_obj" } } };
function a_global_fun(a, b, c) {
// a_global_fun 执行
debugger;
var local_var = "local_var_level";
let local_let = "local_let_level";
return function fun_level_1(name) {
// fun_level_1 执行
debugger;
var local_var_level_1 = "local_var_level_1";
let local_let_level_1 = "local_let_level_1";
console.log(name);
console.log(local_var);
console.log(local_let);
console.log(local_var_level_1);
console.log(local_let_level_1);
console.log(a_global_obj.a.b.c);
return function fun_level_2(name) {
// fun_level_2 执行
debugger;
var local_var_level_2 = "local_var_level_2";
let local_let_level_2 = "local_let_level_2";
console.log(name);
console.log(local_var);
console.log(local_let);
console.log(local_var_level_1);
console.log(local_let_level_1);
console.log(local_var_level_2);
console.log(local_let_level_2);
};
};
}
// 脚本
// (2): 执行一部分
debugger;
// 执行
a_global_fun(1, 2, 3, 4)("level_1")("level_2");