debugger 查看 Scope,理解变量的查找规则

379 阅读1分钟

通过在js文件增加debugger;查看运行期 Scope变化,来理解变量的查找规则;

执行前 scope

image.png

  • 可以 理解为堆栈,隐藏查找规则;
  • 脚本块包括 Global和Script 两个;
  • 变量查询是从上到下,即可Script,再Global;
  • 在执行前,存在的变量名是编译阶段处理,返回声明对象集合;

执行后

image.png

  • 变量赋值了

a_global_fun 函数执行

image.png

  • 当前函数声明 存储在 Local类型,压入栈;
  • Local中变量包括函数形参、变量、this;
  • 站在a_global_fun函数内,查找变量的属性是依次查找 Local、Script、Global ,找不到则抛出ReferenceError;

fun_level_1 函数执行

image.png

  • 当前函数声明 存储在 Local类型,压入栈;
  • Local栈之前栈,由于当前函数引用了外部函数的声明,形成闭包,因此类型标记为 Closure类型;
  • Script和Global依次不变;

fun_level_2 函数执行

image.png

  • 此时堆栈长度是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");