深入理解 JS| 青训营笔记

82 阅读4分钟

1. JS 的基本概念

诞生:1995年,Brendan Eich 开发

  1. 借鉴 C 语言的基本语法
  2. 借鉴 Java 语言的数据类型和内存管理
  3. 借鉴 Scheme 语言,将函数提升到“第一等公民”(first class)的地位
  4. 借鉴 Self 语言,使用基于原型(prototype)的继承机制

发展

  1. Mocha ->1995.9 LiveScript ->1995.12 JavaScript
  2. 1997年6月,第一版 ECMAScript 发布
  3. 1999年12月,第三版 ECMAScript 发布
  4. 2009年12月,第五版 ECMAScript 发布
  5. 2009年,Ryan 创建了 Node.js
  6. 2010年,Isaac 基于 node.js 写出了 npm
  7. 2015年6月,第六版 ECMAScript 发布

1.drawio.png

  • 单线程
  • 动态、弱类型
  • 面向对象、函数式
  • 解释类语言、JIT
  • 安全、性能差
  • ……
  • 动态语言(弱类型语言) 是运行时才确定数据类型的语言,变量在使用前无需申明类型

    const company = 'ByteDance';

  • 静态语言(强类型语言) 是编译时变量的数据类型就需要确定的语言

    String company = 'ByteDance';

2.drawio.png

1.1 数据类型

3.drawio.png

1.2 作用域

变量的可访问性和可见性

静态作用域,通过它就能够预测代码在执行过程中如何查找标识符

  • 全局作用域
  • 函数作用域
  • 块级作用域

1.3 变量提升

变量提升是指在 JavaScript 代码执行过程中,JavaScript 引擎把变量的声明部分和函数的声明部分提升到代码开头的行为。变量被提升后,会给变量设置默认值为 undefined。

console.log('company',company);
console.log('dep',dep);
console.log('myname',myname);
showInfo();
show();
​
const company = "ByteDance";
let dep = "边缘云";
var myname = "name";
​
function showInfo() {
    console.log(company,dep,myname);
    console.log(myname);
}
​
var show = function() {
    console.log(myname);
}
  • var 有变量提升
  • let、const 没有变量提升,提前访问会报错
  • function 函数可以先调用再定义
  • 赋值给变量的函数无法提前使用

2. JS 是怎么执行的

4.drawio.png

const company = "ByteDance";

[    {        "type": "Keyword",        "value": "const"    },    {        "type": "Identifier",        "value": "company"    },    {        "type": "Punctuator",        "value": "="    },    {        "type": "String",        "value": ""ByteDance""    },    {        "type": "Punctuator",        "value": ";"    }]
{
    "type": "Program",
    "body": [
        {
            "type": "variableDeclaration",
            "declarations": [
                {
                    "type": "variableDeclarator",
                    "id": {
                        "type": "Identifier",
                        "name": "company"
                    },
                    "init": {
                        "type": "Literal",
                        "value": "ByteDance",
                        "raw": ""ByteDance""
                    }
                }
            ],
            "kind": "const"
        }
    ],
    "sourceType": "script"
}

当 JS 引擎解析到可执行代码片段(通常是函数调用)的时候,就会先做一些执行前的准备工作,这个准备工作,就叫做“执行上下文(execution context 简称 EC) ”,也叫执行环境 。

5.drawio.png

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

6.drawio.png

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

  • 绑定 This
  • 创建词法环境
  • 创建变量环境
  • 词法环境:基于 ECMAScript 代码的词法嵌套结构来定义标识符和具体变量和函数的关联。一个词法环境由环境记录器和一个可能的引用外部词法环境的空值组成
  • 变量环境:变量环境和词法环境的一个不同就是前者被用来存储函数声明和变量(let 和 const)绑定,而后者只用来存储 var 变量绑定
  • Outer:指向外部变量环境的一个指针

7.drawio.png

8.drawio.png

9.drawio.png

3. JS 的进阶知识点

3.1 闭包

通常,如果引用闭包的函数是一个全局变量,那么闭包会一直存在直到页面关闭;但如果这个闭包以后不再使用的话,就会造成内存泄漏。如果引用闭包的函数是个局部变量,等函数销毁后,在下次 JavaScript 引擎执行垃圾回收时,判断闭包这块内容如果已经不再被使用了,那么 JavaScript 引擎的垃圾回收器就会回收这块内存。

10.drawio.png

3.2 this

  • 普通函数的 this 指向 windows
  1. 对象调用指向对象
  2. 先赋值再调用,看调用的地方
  1. 创建临时对象
  2. 将 this 指向临时对象
  3. 执行构造函数
  4. 返回临时对象

3.3 垃圾回收

11.drawio.png

3.4 事件循环

12.drawio.png

4. 课程总结

  1. JS 是单线程的,但是 Render 进程里面有多个线程
  2. JS 线程和 GUI 线程互斥,执行大的计算任务会导致页面卡顿
  3. 基础数据类型存在栈上,复杂数据类型存在堆上
  4. const、let 没有变量提升,提前使用会报错
  5. JS 也有编译的过程,执行之前会生成执行上下文
  6. 一个执行上下文包括变量环境、词法环境、this、可执行代码
  7. 变量环境里面有一个指向外部函数执行上下文的指针,形成了作用域链
  8. 全局执行上下文只有一份
  9. this 和执行上下文绑定