深入理解JS|青训营笔记

54 阅读5分钟

前言
记录青训营前端专场的学习过程,有不足的地方还请大佬指正。
由于本人基础比较薄弱,所以笔记尽可能的详细。

该文章开始的版本将以简述课程知识点为主,等后面实践有自己的理解后会编辑添加自己的理解

JS的基本概念

作用域

截屏2023-04-28 10.23.08.png

变量提升

console.log('company',company);
console.log('dep',dep);
console.log('myname',myname);
showInfo();
show();

const company = "Bytedance";
let dep = "边缘云";
var myname = "zhangqi"

function showInfo(){
    console.log(company, dep, myname);
    console.log(myname);
}

var show = function(){
console.log(myname);
}

改代码会报错,说company没有初始化。

  • var变量有变量提升(即可以在定以前访问)
  • let、const没有变量提升,提前访问会报错
  • function函数可以先调用再定义
  • 赋值给变量的函数无法提前调用

javascript执行流程

1、源代码通过词法分析、语法分析来生成AST(抽象语法树) 2、通过抽象语法树来生成字节码 3、执行

执行上下文:当js引擎解析到可执行代码片段(通常是函数调用)的时候,就会做一些执行前的准备工作,这个准备工作,就叫做“执行上下文”

截屏2023-04-28 10.45.04.png

  • 全局执行上下文:代码开始执行时就会创建,将它压进栈底,每个生命周期只有一份
  • 函数执行上下文:当执行一个函数时,这个函数内的代码就会被编译、生成变量环境、词法环境等,当函数执行结束的时该执行环境从栈顶弹出

js创建执行上下文的时候做了什么

  • 创建词法环境对象:用于存储变量和函数声明。词法环境有两种类型:全局环境和函数环境
  • 创建变量环境对象:用于存储当前上下文的变量声明
  • 确定this关键字的指向,这取决于函数被调用的方式,例如函数是否被作为方法调用、使用apply()或call()方法,还是在全局作用域中调用

执行上下文在概念上表示如下

  ThisBinding = <this value>,
  LexicalEnvironment = { ... },
  VariableEnvironment = { ... },
}

this绑定

在全局执行上下文中,this的值指向全局对象。(在浏览器中,this指向window)

在函数执行上下文中,this 的值取决于该函数是如何被调用的。如果它被一个引用对象调用,那么 this 会被设置成那个对象,否则 this 的值被设置为全局对象或者 undefined(在严格模式下)。

let foo = {
  baz: function() {
  console.log(this);
  }
}

foo.baz();   // 'this' 引用 'foo', 因为 'baz' 被
             // 对象 'foo' 调用

let bar = foo.baz;

bar();       // 'this' 指向全局 window 对象,因为
             // 没有指定引用对象

词法环境

简单理解:词法环境是一种持有标识符——变量映射的结构。(标识符指的是变量/函数的名字,而变量是对实际对象[包括函数类型对象]或原始数据的引用)。词法环境在函数创建时就被创建

词法环境内部有两个组件:(1)环境记录器 (2)外部环境的引用

  1. 环境记录器是存储变量和函数声明的实际位置。
  2. 外部环境的引用意味着它可以访问其父级词法环境(作用域)。

词法环境有两种类型:

  • 全局环境(在全局执行上下文中)是没有外部环境引用的词法环境。全局环境的外部环境引用是 null。它拥有内建的 Object/Array/等、在环境记录器内的原型函数(关联全局对象,比如 window 对象)还有任何用户定义的全局变量,并且 this的值指向全局对象。
  • 函数环境中,函数内部用户定义的变量存储在环境记录器中。并且引用的外部环境可能是全局环境,或者任何包含此内部函数的外部函数。

环境记录器也有两种类型:

  • 声明式环境记录器存储变量、函数和参数。
  • 对象环境记录器用来定义出现在全局上下文中的变量和函数的关系。

简而言之,

  • 全局环境中,环境记录器是对象环境记录器。
  • 函数环境中,环境记录器是声明式环境记录器。
  • 特殊情况,在catchwith语句的代码块时,环境记录器是声明式环境记录器

注意 —  对于函数环境声明式环境记录器还包含了一个传递给函数的 arguments 对象(此对象存储索引和参数的映射)和传递给函数的参数的 length

  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // 在这里绑定标识符
    }
    outer: <null>
  }
}

FunctionExectionContext = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // 在这里绑定标识符
    }
    outer: <Global or outer function environment reference>
  }
}

变量环境

它同样是一个词法环境,拥有和词法环境一样的属性(键值对)其环境记录器持有变量声明语句在执行上下文中创建的绑定关系。

词法环境组件和变量环境的一个不同就是前者被用来存储函数声明和变量(let 和 const)绑定,而后者只用来存储 var 变量绑定。

let a = 20;
const b = 30;
var c;

function multiply(e, f) {
 var g = 20;
 return e * f * g;
}

c = multiply(20, 30);

它的执行上下文

GlobalExectionContext = {

  ThisBinding: <Global Object>,

  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // 在这里绑定标识符
      a: < uninitialized >,
      b: < uninitialized >,
      multiply: < func >
    }
    outer: <null>
  },

  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // 在这里绑定标识符
      c: undefined,
    }
    outer: <null>
  }
}

FunctionExectionContext = {
  ThisBinding: <Global Object>,

  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // 在这里绑定标识符
      Arguments: {0: 20, 1: 30, length: 2},
    },
    outer: <GlobalLexicalEnvironment>
  },

VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // 在这里绑定标识符
      g: undefined
    },
    outer: <GlobalLexicalEnvironment>
  }
}

引用文章:juejin.cn/post/684490…