UP程序员Sunday一小时读完红宝书--《JavaScript 高级程序设计(第四版)》

今天跟随B站UP主/公众号程序员Sunday过了一遍被称为JS红宝书的《JavaScript 高级程序设计(第四版)》,但其实除了前面几张,大部分内容都没有听懂。因此,下载了Sunday老师github发布的文档,下载链接:https://github.com/lgd8981289/book_read_quickly

下载的Sunday老师的部分文档内容如下,也欢迎大家关注我的公众号GISideas,获取更多内容啊!

一小时读完红宝书

《JavaScript 高级程序设计(第四版)》一直被认为是 js 的圣经。里面包含了几乎所有 js 的知识和实用技术。特别适合想要学习或者精进 JS 的开发者阅读。


hello,大家好,我是 Sunday。

有很多小伙伴跟我留言说:Sunday 老师,讲一下红宝书吧。

那么这一次,它来啦~

整个红宝书的内容其实是非常多的,一共有 28 章。

整体的内容全部都是围绕着 js 展开。从最基础的《什么是 js 开始》,中间涉及到《动画、canvas》,到最后讲到《网络请求、worker 线程、最佳实践》。几乎是涵盖了整个 js 所有需要学习的内容。

如果你在工作中,对 js 有哪些不明确的地方,那么它应该都可以给你提供一些文档支持。

不过 ,28 章的内容确实有点多,所以我们把它划分为了三大部分:

  1. 基础部分:主要讲解 JS 基础知识,1 - 11 章
  2. API 部分:主要讲解 浏览器、DOM 等相关的 API。12 - 20 章
  3. 开发实用技术:主要讲解了一下开发的实用方案。

那么下面,咱们就来看看,这本一直被人称赞的《红宝书》。


一:基础部分

整本书从第一章开始,到第十一章为止。所讲解的都是 js 最基础的部分。

01:什么是 JavaScript

这一章主要讲解了两部分的内容:

  1. js 基本概念
  2. es 基本概念

咱们主要来看 js 就可以。

js 包含三部分:

  1. ECMAScript 也就是 eses 被称为是 js 的核心,在 2015 年 之后几乎保持着每年发布一版的频率。其中 2015 年 发布的 ESMAScript 第六版 被称为 ES6,如果用年费来表示的话就是 ES 2015。后续也同样维持着同样的叫法,比如:2016 年 发布第七版,被称作 ES7ES 2016

  2. DOM: 文档对象模型。它是一组应用编程接口的 API,可以直接控制整个页面的节点。
    比如,这样一段 HTML 页面:

    image-20230715175747522

    通过 DOM 就可以表示为一组分层节点:

    image-20230715175809486
  3. BOM:它表示 浏览器对象模型API。主要用来操作浏览器窗口。比如我们常用的 window 对象,就属于 BOM 对象。

02:HTML 中的 JavaScript

核心内容分为了 3 个部分:

  1. 使用 <script> 元素的方式: 引入 <script> 标签一般可以在两个地方做:
    1. header 标签的最后:但是这样会意味着,浏览器必须把所有 JavaScript 代码都下载、解析完成后,才能开始渲染页面。这就会导致在最初时页面空白。
    2. body 标签的最后:这样就不会影响页面渲染了。
  2. 行内脚本和外部脚本的区别: 所谓行内脚本就是直接把 JS 写到 html 文件里面。这种方式肯定是不被推荐的。推荐使用外部脚本,也就是:以 script 标签的形式引入。
  3. js 不可用时,如何保证用户体验: html 提供了一个 noscript 标签,可以在 不支持脚本运行 的浏览器中显示。

03:语言基础

这一章主要讲解的就是 JS 中的一些基础语法,比如:如何声明变量啦、如何判断数据类型啦。

整体的内容因为偏向基础部分,所以咱们主要就挑选其中一些易错的语法,来给大家进行讲解。

这些语法一共有:

  1. typeof 操作符typeof 是用来判断数据类型的语法。它的返回值是固定的几种类型。同时需要注意 typeof null === 'object'

  2. 位操作符:位操作符一向是很多小伙伴不太熟悉的领域。所谓的 “位”,指的是 操作内存中表示数据的比特(位)。一般以 32 位 的整数进行表示。

    咱们来看下面这个图:
    image-20230716104518338
    10010 表示为十进制的 18。那么咱们来看一下它的计算方式:

    这里的每一位都代表 2 的幂, 第一位(称为第 0 位)表示 2^0 ,第二位表示 2^1 ,依此类推。

    如果一个位是空的,则以0填充,相当于忽略不计。
    除此之外,作者还在书中提到了 7 种按位运算。

    1. 按位非:用波浪符(~)表示,它的作用是返回数值的一补数。即:由0变为1
    2. 按位与:按位与操作在两个位都是 1 时返回 1,在任何一位是 0 时返回 0。
    3. 按位或:按位或操作在至少一位是 1 时返回 1,两位都是 0 时返回 0。
    4. 按位异或:按位异或与按位或的区别是,它只在一位上是 1 的时候返回 1(两位都是 1 或 0,则返回 0)。
    5. 左移:按照指定的位数将数值的所有位向左移动
    6. 有符号右移:会将数值的所有 32 位都向右移,同时保留符号
    7. 无符号右移:会将数值的所有 32 位都向右移
  3. with 语句:咱们在 vuejs 设计与实现 的编译器环节看到过。with 语句的用途是将代码作用域设置为特定的对象。

04:变量、作用域与内存

本章的内容主要就是三部分:

  1. 变量: 变量分为两种类型:
    1. 简单数据类型:数据保存在栈中,通过变量直接引用
    2. 复杂数据类型:数据保存在堆中,变量无法直接引用到堆,所以需要在栈中保存一个内存地址,通过内存地址指向堆内存。
  2. 作用域: 作用域没有什么复杂度,主要理解上下文即可。
  3. 内存: 指的就是 垃圾回收机制。大致分为两种:
    1. 引用计数:在 循环引用 时出现错误
    2. 标记清理:目前浏览器中最常用的垃圾回收策略

05:基本引用类型

所谓基本引用类型,就是一些基本的 构造函数使用,这里作者提供了几个基本的对象,并且讲解了一些它们的用法。

咱们可以根据脑图大致的过一下。

06:集合引用类型

集合引用类型的内容就比较多了。

主要集中在 其他引用类型 部分。这部分内容一共分为 7 类:

  1. ArrayBufferArrayBuffer() 是一个普通的 JavaScript 构造函数,可用于 在内存中分配特定数量的字节空间
  2. DataView:可以从二进制 ArrayBuffer 对象中读写多种数值类型的底层接口
  3. 定型数组:定型数组是另一种形式的 ArrayBuffer 视图
  4. Map:具备真正的 键/值 存储机制。
  5. WeakMap:表示“弱映射”的集合。WeakMap 中的 “weak”(弱),描述的是 JavaScript 垃圾回收程序对待“弱映射”中键的方式。意思就是,这些键不属于正式的引用,不会阻止垃圾回收。
  6. Set:值永远都不会重复的数组
  7. WeakSet:“弱集合”

07:迭代器与生成器

迭代器和生成器。这两个特性都是在 ES6 新增的,目的就是:可以更加方便的实现迭代

所谓迭代指的就是:按照顺序反复多次执行一段程序,通常会有明确的终止条件。 比如常见的循环就是迭代器的一种简单实现。

但是基本的循环方式,随着代码量增加,代码会变得越发混乱。很多语言都通过原生语言结构解决了这个问题,开发者无须事先知道如何迭代就能实现迭代操作。这个解决方案就是 迭代器模式

迭代器模式描述了一个方案,即 可以把有些结构称为“可迭代对象”(iterable),因为它们实现了正式的 Iterable 接口,而且可以通过迭代器 Iterator 消费。

而生成器的形式是一个 函数,函数名称前面加一个星号**(*)**表示它是一个生成器。只要是可以定义函数的地方,就可以定义生成器。

生成器会返回一个迭代器对象。

生成器中存在一个 yield 关键字。

yield 关键字可以让生成器停止和开始执行,也是生成器最有用的地方。

生成器函数在遇到 yield 关键字之前会正常执行。遇到这个关键字后,执行会停止,函数作用域的状态会被保留。停止执行的生成器函数只能通过在生成器对象上调用 next() 方法来恢复执行:

08:对象、类与面向对象编程

本章的主要内容有三部分:

  1. 对象的创建过程
  2. js 的继承机制
  3. js 中的类

对象的创建过程:

在这里作者通过 4 种模式来讲解了对象的创建过程

  1. 工厂模式:通过一个 函数(工厂) 不断地生成新的对象
  2. 构造函数模式:构造函数模式配合 new 关键字使用
  3. 原型模式:每个函数都会创建一个 prototype 属性,这个属性是一个对象,包含应该由特定引用类型的实例共享的属性和方法。实际上,这个对象就是通过调用构造函数创建的对象的原型。使用原型对象的好处是,在它上面定义的属性和方法可以被对象实例共享。原来在构造函数中直接赋给对象实例的值,可以直接赋值给它们的原型:
  4. 对象迭代:直接通过一个包含所有属性和方法的对象字面量来重写原型成为了一种常见的做法

js 的继承机制:

JS 的继承主要是通过 原型链 实现的。其基本思想就是通过 原型继承多个引用类型的属性和方法

除此之外,作者还提到了 4 中继承方式:

  1. 组合继承
  2. 原型式继承
  3. 寄生式继承
  4. 寄生式组合继承

js 中的类:

类就是 class 的意思,它是 ES6 之后新增的语法糖,背后使用的仍然是原型和构造函数的概念。这也是目前最推荐的实现继承的方式。

与函数类型相似,定义类也有两种主要方式:类声明和类表达式。这两种方式都使用 class 关键字加大括号:

image-20230717113131605

类可以包含构造函数方法、实例方法、获取函数、设置函数和静态类方法,但这些都不是必需的。空的类定义照样有效。

image-20230731164743462

09:代理与反射

所谓代理指的就是 Proxy,所谓反射指的就是 Reflect。这两个对象咱们之前在书中都有讲解过。

那么下面,咱们就来看下《红宝书》中对代理和反射的解释。

代理:

红宝书首先对代理进行了定义,书中提到:代理是目标对象的抽象。咱们来看这段代码:

image-20230801092439299

在这段代码中,proxy 就被称为代理,也叫做代理对象。target 被叫做目标对象。handler 里可以写入代理行为,被称为 捕获器

想要代理对象,那么主要是通过捕获器(handler)进行的:

image-20230801092459434

那么此时,只要 proxy 触发了 get() 操作,就会触发 get() 捕获器。

所有捕获器都可以访问相应的参数,基于这些参数可以重建被捕获方法的原始行为。比如,get() 捕获器会接收到目标对象、要查询的属性和代理对象三个参数。

image-20230801092646503

有了这些参数,就可以直接利用代理对象获取原始对象的属性:

image-20230801092657251

这些就是基本的代理逻辑。

反射:

处理程序对象中所有可以捕获的方法都有对应的反射(Reflect)API 方法。

比如:可以直接通过 Reflect.get 获取对象的属性。

image-20230801092718376

这里的 argumentstrapTarget, property, receiver 这三个参数。这里就等同于把这三个参数直接放到了 get 方法中。

接下来书中又详细介绍了 Reflect 的更多 API 使用。这里咱们就不一个一个去说了。

10:函数

书中在本章开头就提到:函数是 ECMAScript 中最有意思的部分之一,这主要是因为函数实际上是对象。每个函数都是Function类型的实例,而 Function 也有属性和方法,跟其他引用类型一样。

函数主要有四种定义方式:

首先第一种就是通过 function 关键字 :因为函数是对象,所以函数名就是指向函数对象的指针,而且不一定与函数本身紧密绑定。

image-20230801093120004

第二种是:函数表达式。

image-20230801093128944

第三种就是:箭头函数。

image-20230801093136319

最后一种是使用 Function 构造函数。

image-20230801093143123

注意: 这种方式是不被推荐的。

因为这段代码会被解释两次:第一次是将它当作常规 ECMAScript 代码,第二次是解释传给构造函数的字符串。这显然会影响性能。

递归:

递归函数通常的形式是:一个函数通过名称调用自己

image-20230801093219438

这是经典的递归阶乘函数。

闭包:

闭包指的是:那些 引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的。

image-20230801093301030

这里加粗的代码位于内部函数(匿名函数)中,其中引用了外部函数的变量 propertyName。那么这个内部函数就可以被叫做 闭包

11:期约与异步函数

所谓期约指的是: promise

我们知道 promise 主要就是处理异步编程的,所以,本章的内容主要就是三部分:

  1. 异步编程
  2. promise 期约
  3. 异步函数

异步编程:

在早期的 JavaScript 中,只支持定义回调函数来表明异步操作完成。串联多个异步操作是一个常见的问题,通常需要深度嵌套的回调函数(俗称“回调地狱”)来解决。

比如,这种代码:

image-20230718105346945

promise:

promise 的出现就是为了解决这种回调地狱的问题。

ECMAScript 6 新增的引用类型 Promise,可以通过 new 操作符来实例化。

image-20230718105636248

它的内部有三种状态:

  1. 待定(pending
  2. 兑现(fulfilled,resolved)
  3. 拒绝(rejected

promise 具有两个实例方法:

  1. p.then :可以处理 已兑现 状态
    image-20230718110509985
  2. p.catch :可以处理 已拒绝 状态
    image-20230718110518217

异步函数

所谓异步函数指的就是 “async/await”(语法关键字),它主要是用来配合 promise 进行使用的。

其中 async 关键字用于声明异步函数。这个关键字可以用在函数声明、函数表达式、箭头函数和方法上:

image-20230718110707140

使用 async 关键字可以让函数具有异步特征,但总体上其代码仍然是同步求值的。

await 关键字,必须要在 异步函数 中使用。

await 关键字可以暂停异步函数代码的执行,等待 promise 解决。

image-20230718110957718

第一部分总结

那么到这里,咱们就把第一部分讲解完了。这一部分主要就是 js 的基本语法。

接下来咱们来去看第二部分:API 部分

二、API 部分

这一部分描述了从 12 章到 20 章的内容。

12:BOM

根据章名咱们也可以看出来,这一章主要就是讲解 BOM 对象的。

核心的内容有 4 部分:

  1. window 对象
  2. location 对象
  3. navigator 对象
  4. history 对象

window 对象

BOM 的核心是 window 对象,表示浏览器的实例。

window 对象在浏览器中有两重身份,一个是 ECMAScript 中的 Global 对象,另一个就是浏览器窗口的 JavaScript 接口。这意味着网页中定义的所有对象、变量和函数都以 window 作为其 Global 对象进行访问。

因为 window 对象被复用为 ECMAScriptGlobal 对象,所以通过 var 声明的所有全局变量和函数都会变成 window 对象的属性和方法。

image-20230719101740060

这里,变量 age 和函数 sayAge()被定义在全局作用域中,它们自动成为了 window 对象的成员。

但是需要注意:如果在这里使用 let 或 const 替代 var,则不会把变量添加给全局对象:

image-20230719102854039

location 对象

location 是最有用的 BOM 对象之一,提供了当前窗口中加载文档的信息,以及通常的导航功能。

这个对象独特的地方在于,它既是 window 的属性,也是 document 的属性。也就是说,window.location 和 document.location 指向同一个对象。location 对象不仅保存着当前加载文档的信息,也保存着把 URL 解析为离散片段后能够通过属性访问的信息。

image-20230719103732756

navigator 对象

它的属性通常用于确定 浏览器的类型

它提供了非常多的属性和方法:

image-20230719104306265 image-20230719104326012

history 对象

history 对象表示当前窗口首次使用以来用户的导航历史记录。因为 historywindow 的属性,所以每个 window 都有自己的 history 对象。

通常情况下,我们可以通过它来控制 URL 的前进和后退。

比如,他所提供的 go 方法:

image-20230719104830432

go()有两个简写方法:back() 和 forward()。顾名思义,这两个方法模拟了浏览器的后退按钮和前进按钮:

image-20230719104900267

13:客户端检测

这里的客户端其实指的就是 浏览器 。而所谓的检测主要有三部分:

  1. 能力检测
  2. 用户代理检测
  3. 软件与硬件检测

能力检测:

能力检测(又称特性检测)即在 JavaScript 运行时中使用一套简单的检测逻辑,测试浏览器是否支持某种特性。

能力检测的基本模式如下,通过这个代码可以检测浏览器是否拥有 propertyInQuestion 方法:

image-20230719111058066

用户代理检测:

用户代理检测:通过浏览器的用户代理字符串确定使用的是什么浏览器

想要知道自己代码运行在什么浏览器上,大部分开发者会分析 window.navigator.userAgent 返回的字符串值。

image-20230801095404632

软件与硬件检测:

现代浏览器提供了一组与页面执行环境相关的信息,包括浏览器、操作系统、硬件和周边设备信息。这些属性可以通过暴露在 window.navigator 上的一组 API 获得。

这一部分提供了很多的 API,咱们就不一一介绍了。

14:DOM

DOM 被称为是:文档对象模型。

可以通过 DOM 来表示 由多层节点构成的文档,通过它开发者可以添加、删除和修改页面的各个部分。

本章的主要内容包含了三部分:

  1. 节点层级
  2. DOM 编程
  3. MutationObserver 接口

节点层级

任何 HTML 或 XML 文档都可以用 DOM 表示为一个由节点构成的层级结构。

节点分很多类型,每种类型对应着文档中不同的信息和(或)标记,也都有自己不同的特性、数据和方法,而且与其他类型有某种关系。

这些关系构成了层级,让标记可以表示为一个以特定节点为根的树形结构。

以下面的 HTML为例:

image-20230719114522312

如果用层级表示,则是这样的:

image-20230719114538151

DOM 编程

所谓的 DOM 编程 其实指的就是:通过 JS 操作 DOM

咱们来看一个 动态插入 <script> 标签的例子

image-20230719115328843

<script> 元素用于向网页中插入 JavaScript 代码,可以是 src 属性包含的外部文件,也可以是作为该元素内容的源代码。

MutationObserver 接口

MutationObserver 接口,可以在 DOM 被修改时异步执行回调。使用 MutationObserver 可以观察整个文档、DOM 树的一部分,或某个元素。

书中详细的讲解了它的基本用法:

MutationObserver 的实例要通过调用 MutationObserver 构造函数并传入一个回调函数来创建:

image-20230719120331975

observe 方法

新创建的 MutationObserver 实例不会关联 DOM 的任何部分。

要把这个 observerDOM 关联起来,需要使用 observe() 方法。

这个方法接收两个必需的参数:

  1. 要观察其变化的 DOM 节点
  2. 一个 配置 对象。

image-20230719120507681

执行以上代码后,<body> 元素上任何属性发生变化都会被这个 MutationObserver 实例发现,然后就会异步执行注册的回调函数。

15:DOM 扩展

本章的内容主要就是两部分:

  1. Selectors API
  2. HTML5 DOM 扩展

Selectors API

Selectors API 主要指的就是获取 DOM 元素 的方法,这里的 API 主要有三个:

  1. querySelector()
  2. querySelectorAll()
  3. matches():接收一个 CSS 选择符参数,如果元素匹配则该选择符返回 true,否则返回 false

HTML5 DOM 扩展

HTML5 新增了很多的扩展内容,比如:

  1. CSS 类扩展:比如 dcument.getElementsByClassName()

  2. 焦点管理:比如 dom.focus() 获取焦点的方法

  3. HTMLDocument 扩展:比如 document.head 获取 <header> 标签元素

  4. 字符集属性:比如 document.characterSet 获取字符集(UTF-16 || UTF-8

  5. 自定义数据属性:比如 使用前缀 data- 以便告诉浏览器,这些属性既不包含与渲染有关的信息,也不包含元素的语义信息。

  6. 插入标记:比如 innterHTML 属性

  7. scrollIntoView():这个 API 可能很多小伙伴没有遇到过,它的作用是:滚动选中元素的父元素,使选中元素可以被用户可见。

    document.getElementById('nav-footer').scrollIntoView();
    

    比如我们可以通过这种方式,来让 nav-footer 元素被用户可见。

16:DOM2 和 DOM3

本章主要讲解了三部分的内容:

  1. DOM2 到 DOM3 的变化
  2. 操作样式的 DOM API
  3. DOM 遍历与范围

DOM2 到 DOM3 的变化

DOM2DOM3 指的其实是 DOM 2级DOM 3级

所谓的每一级其实指的是 在原有的级别上增加了一些扩充的事件

比如:DOM1(DOM Level 1)主要定义了 HTML 和 XML 文档的底层结构。

DOM2 级在原来 DOM 的基础上又扩充了鼠标、用户界面事件、范围、遍历等细分模块。

DOM3进一步扩展了 DOM,新增了比如:DOM 加载和保存模块、DOM验证模块 等等。

**操作样式的 DOM API **

任何支持 style 属性的 HTML 元素在 JavaScript 中都会有一个对应的 style 属性。

HTML style 属性中的 CSS 属性在 JavaScript style 对象中都有对应的属性:

image-20230720131453035

这个表中列举出来的属性知识一部分,实际的属性非常多,咱们就不一个一个进行列举了。

DOM 遍历与范围

DOM 遍历是对 DOM 结构的深度优先遍历至少允许朝两个方向移动(取决于类型)

遍历以给定节点为根,不能在 DOM 中向上超越这个根节点:

我们以这段代码为例:

image-20230720131933127

这段代码构成的 DOM 树如图

image-20230720132006522

其中的任何节点都可以成为遍历的根节点。

比如,假设以<body>元素作为遍历的根节点,那么接下来是<p>元素、<b>元素和两个文本节点(都是<body>元素的后代)。

但这个遍历不会到达<html>元素、<head>元素,或者其他不属于<body>元素子树的元素。

而以 document 为根节点的遍历,则可以访问到文档中的所有节点:

image-20230720132056285

17:事件

主要是五个部分:

  1. 事件流
  2. 使用事件处理程序
  3. 事件对象
  4. 事件类型
  5. 事件委托

事件流

事件流描述了 页面接收事件的顺序。大体分为两类:

  1. 事件冒泡
  2. 事件捕获

事件冒泡

IE 事件流被称为事件冒泡:事件被定义为从最具体的元素(文档树中最深的节点)开始触发,然后向上传播至没有那么具体的元素(文档)。

我们以这个代码为例:

image-20230720164018272

它的事件流传输过程为:

image-20230720164032719

事件捕获

事件捕获的意思是:最不具体的节点应该最先收到事件,而最具体的节点应该最后收到事件。

同样以这个示例:

image-20230720164018272

它的事件流传输过程为:

image-20230720164132855

在现在的 DOM 事件流中,一个完整的事件流程被分为三个阶段:事件捕获、到达目标和事件冒泡。

image-20230720164231393

使用事件处理程序

事件意味着 用户或浏览器执行的某种动作(clickload

为响应事件而调用的函数 被称为事件处理程序(或事件监听器)。

事件处理程序的名字以"on"开头,因此 click 事件的处理程序叫作 onclick,而 load 事件的处理程序叫作 onload

事件对象

DOM 中发生事件时,所有相关信息都会被收集并存储在一个名为 event 的对象中。这个 event 对象就被成为 事件对象

DOM 合规的浏览器中,event 对象是传给事件处理程序的唯一参数。

不管以哪种方式指定事件处理程序,都会传入这个 event 对象。

image-20230720164547066

事件类型

DOM 中的事件类型有很多。作者在书中提到, DOM3 定义的事件类型有以下 7 种

其中每一个大类型还包含了很多具体的事件类型。这块的内容非常的多,涉及到了各种事件的使用方式。

咱们就不一个一个去说了。

事件委托

JavaScript 中,页面中事件处理程序的数量与页面整体性能直接相关,原因大体有两点:

  • 首先:每个函数都是对象,都占用内存空间,对象越多,性能越差。
  • 其次:为指定事件处理程序所需访问 DOM 的次数会先期造成整个页面交互的延迟。

那么想要处理这种情况,作者给我们提供了一种方式,就是 事件委托

事件委托利用事件冒泡,可以只使用一个事件处理程序来管理一种类型的事件。

比如:

image-20230720165627396

这里的 HTML 包含 3 个列表项,在被点击时应该执行某个操作。对此,通常的做法是像这样指定 3 个事件处理程序(非事件委托):

image-20230720165653567

如果对页面中所有需要使用 onclick 事件处理程序的元素都如法炮制,结果就会出现大片雷同的代码。

使用事件委托,只要给所有元素共同的祖先节点添加一个事件处理程序,就可以解决问题:

image-20230720165726402

18:动画与 Canvas 图形

主要分为4部分:

  1. requestAnimationFrame API
  2. <canvas> 标签
  3. 绘制 2D 图形的方式
  4. WebGL 绘制 3D 图形

本章的内容其实是比较复杂的,涉及到了 canvas、webglAPI 的使用。

其中后三部分涉及到了大量的 API,咱们没有办法在这次视频中进行讲解。所以针对本章主要就说明下第一部分 requestAnimationFrame API

requestAnimationFrame 是一个配合动画执行的 API

它会在浏览器下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。

在没有 requestAnimationFrame 之前, JavaScript 中创建动画基本上就是使用 setInterval() 来控制动画的执行。

image-20230721095113878

比如,上面的代码:每间隔 100 毫秒执行特定的方法。

但是,这样的代码其实是有一些问题的。比如 时间间隔 的问题。

我们知道 setInterval 的第二个参数的延时,只能保证何时会把代码添加到浏览器的任务队列,不能保证添加到队列就会立即运行。

如果队列前面还有其他任务,那么就要等这些任务执行完再执行。

简单来讲,这里毫秒延时并不是说何时这些代码会执行,而只是说到时候会把回调加到任务队列。

如果添加到队列后,主线程还被其他任务占用,比如正在处理用户操作,那么回调就不会马上执行。

那么就可能导致动画不够平滑。

requestAnimationFrame 则会在浏览器下一次重绘之前执行,这样就保证了执行时机的问题。

image-20230721120534964

19:表单脚本

内容大致分为了三部分:

  1. 表单基础
  2. 一些表单控件的验证和交互用法
  3. 富文本编辑

表单基础

Web 表单在 HTML 中以<form>元素表示,在 JavaScript 中则以 HTMLFormElement 类型表示。

比如,我们可以通过简单的 getElementById() 来获取表单:

接下来作者又提到了一些表单的基础行为,比如:

  1. 表单提交
  2. 表单验证
  3. 重置表单

一些表单控件的验证和交互用法

表单的控件有很多,比如:

  1. 文本框控件:单行可以使用 input 元素,多行可以使用 textarea 元素
  2. 选择框控件:<select>和<option>

除此之外,表单控件还提供了很多的方法:

  1. 选中文本:select() 方法
    image-20230721104332345

  2. 屏蔽特殊文本:验证 charCode

    image-20230721104429408
  3. 约束验证:required 标记:
    image-20230721104530887

这部分内容并不复杂,属于基础的东西。所以咱们把一些关键的场景列举出来,就不再细说了。

富文本编辑

富文本编辑在现在的开发中是一个常用的需求。咱们大多数时候都会通过一些 富文本的库来去实现这个功能。

作者在书中介绍了一些 富文本编辑的底层实现逻辑,咱们一起来看一下。

富文本实现的基本技术就是:在空白 HTML 文件中嵌入一个 iframe

image-20230721105654217

通过 designMode 属性,可以将这个空白文档变成可以编辑的,实际编辑的则是<body>元素的 HTML

designMode 属性有两个可能的值:"off"(默认值)和"on"

设置为"on"时,整个文档都会变成可以编辑的(显示插入光标),从而可以像使用文字处理程序一样编辑文本,通过键盘将文本标记为粗体、斜体,等等。

20:JavaScript API

这一章的内容特别的多,详细的介绍了 JS 的各种 API 使用方式,总共包含了12 类:

  1. Atomics 与 SharedArrayBuffer:
    1. SharedArrayBuffer:用来表示一个通用的、固定长度的原始二进制数据缓冲区
    2. Atomics:强制同一时刻只能对缓冲区执行一个操作,可以让多个上下文安全地读写一个 SharedArrayBuffer
  2. **跨上下文消息:**在不同执行上下文(如不同工作线程或不同源的页面)间传递信息的能力
  3. Encoding API: 实现字符串与定型数组之间的转换
  4. File API 与 Blob API:
    1. File API:文件本身
    2. Blob API:文件数据对象(数据本身)
  5. **媒体元素:**即 ,从而为浏览器提供了嵌入音频和视频的统一解决方案。
  6. 拖放:
    1. dragstart
    2. drag
    3. dragend
  7. Notifications API: 用于向用户显示通知
  8. Page Visibility API: 页面对用户是否可见的信息
  9. Streams API: 把一个大数据块拆分为多个小数据块分开处理
  10. 计时 API: 检测页面性能指标
  11. **Web 组件:**一套用于增强 DOM 行为的工具,包括影子 DOM、自定义元素和 HTML 模板
  12. **Web Cryptography API:**一套密码学工具,规范了 JavaScript 如何以安全和符合惯例的方式实现加密

第二部分总结

第二部分主要介绍了 浏览器、DOM 等相关的 API。

那么接下来咱们来看第三部分:开发实用技术。

三:开发实用技术

第三部分也是全书中最后一部分的内容。

21:错误处理与调试

本章的内容主要分为三个部分:

  1. 理解浏览器错误报告
  2. 处理错误
  3. 调试 JavaScript 代码

理解浏览器错误报告

浏览器的错误报告会 展示在控制台 中。

如果想要查看错误,那么需要进入到浏览器的控制台。

而在移动端上,想要查看错误报告,则需要使用到一些其他的工具。这里作者并没有详细给出介绍。只是提出了几个方案:

  1. Chrome 的操作步骤参见 Google Developers 网站的文章《Android 设备的远程调试入门》
  2. Safari 的操作步骤参见 Apple Developer 网站的文章“Safari Web Inspector Guide”。
  3. Firefox 常用的调试工具是 Firebug Lite

处理错误

JS 中想要捕获错误,那么需要通过 tey/catch 的形式进行捕获。

image-20230722153606958

任何可能出错的代码都应该放到 try 块中,而处理错误的代码则放在 catch 块中。如果 try 块中有代码发生错误,代码会立即退出执行,并跳到 catch 块中。catch 块此时接收到一个对象,该对象包含发生错误的相关信息。

try/catch 语句中可选的 finally 子句始终运行。

如果 try 块中的代码运行完,则接着执行finally 块中的代码。如果出错并执行 catch 块中的代码,则 finally 块中的代码仍执行。trycatch 块无法阻止 finally 块执行,包括 return 语句。

image-20230722153727736

调试 JavaScript 代码

这里作者提供了三种方式:

  1. 通过 console 进行控制台打印
  2. 通过 debugger 关键字调试
  3. 通过 throw new Error 抛出错误

22:处理 XML + 23:JSON

22和23 章的内容,咱们一块进行查看。

首先咱们先来看一下什么是 XML

image-20230722155428878

XML 被设计用来传输和存储数据(和 JSON 类似)。以上的这段 XML 可以用以下 JSON 表示:

image-20230722155538987

在现在的数据处理中,XML 已经非常少见了,大部分都是通过 JSON 进行处理。

所以说,对于 22 章的内容,咱们没有必要再去学习,直接查看 23章:json 即可。

json 是目前主流的数据传输格式,他支持以下几种形式:

image-20230722160413575
  • 简单值
  • 对象
  • 数组

JSON 支持序列化和解析。

所谓序列化指的是:通过 JSON.stringify() 方法,把一个对象变为 json 格式的字符串。

解析指的是:通过 JSON.parse() 方法,把 json 格式的字符串转化为 对象。

24:网络请求与远程资源

内容主要分成 5 个部分:

  • 使用 XMLHttpRequest 对象
  • 处理 XMLHttpRequest 事件
  • 源域 Ajax 限制
  • Fetch API
  • WebSocket

使用 XMLHttpRequest 对象

XMLHttpRequest 简称为 XHR,是处理 ajax 网络请求的基类。

下面这段代码,描述了 XHR 的基本使用:

image-20230722162836001

在上面的代码中,使用 new 关键字得到了 xhr 的实例。

处理 XMLHttpRequest 事件

处理 XHR 事件指的是处理 进度事件

这些事件一共有 6 种:

  • loadstart:在接收到响应的第一个字节时触发。
  • progress:在接收响应期间反复触发。
  • error:在请求出错时触发。
  • abort:在调用 abort() 终止连接时触发。
  • load:在成功接收完响应时触发。
  • loadend:在通信完成时,且在 errorabortload 之后触发。

想要处理事件,那么可以通过 xhr. 的形式处理,下面以 load 为例进行演示:

image-20230722163346224

源域 Ajax 限制

通过 XHR 进行 Ajax 通信的一个主要限制是 跨源安全策略。默认情况下,XHR 只能访问与发起请求的页面在同一个域内的资源。

而想要解决这个问题,则需要通过 CORS

跨源资源共享CORS,Cross-Origin Resource Sharing)定义了 浏览器与服务器如何实现跨源通信

**Fetch API **

直接的 XHR 请求比较复杂,所以也可以通过 ``Fetch API 进行处理。

Fetch API 是目前 js 原生支持的 ajax 请求对象。可以返回 promise 的实例:

image-20230722164753887

目前 fetch API 在实际开发中使用并不会多,大多数会通过 axios 进行处理。

WebSocket

Web Socket(套接字)的目标是:通过一个长时连接实现与服务器全双工、双向的通信

JavaScript 中创建 Web Socket 时,一个 HTTP 请求会发送到服务器以初始化连接。

服务器响应后,连接使用的 HTTP 协议会切换到 Web Socket 协议。

这意味着 Web Socket 不能通过标准 HTTP 服务器实现,而必须使用支持该协议的专有服务器。

接下来咱们来看一段 web socket 的基本代码,分为:

  1. 创建链接
  2. 发送事件
  3. 响应事件
image-20230722165417741

25:客户端存储

所谓的客户端存储大致分为三类:

  • cookie
  • 浏览器存储 API
  • IndexedDB

cookie

cookie,最初用于 在客户端存储会话信息

这个规范要求服务器在响应 HTTP 请求时,通过发送 Set-Cookie HTTP 头部包含会话信息

image-20230722165823943

**浏览器存储 API **

所谓浏览器存储 API 指的就是 Web Storage

这个 Storage 分为:

  1. sessionStorage:只存储会话数据,这意味着数据只会存储到浏览器关闭。
  2. localStorage:作为在客户端持久存储数据的机制。数据不会跟随浏览器关闭消失。

sessionStoragelocalStorage 提供了同样的操作方法,主要有以下四个:

  • clear():删除所有值;不在 Firefox 中实现。
  • getItem(*name*):取得给定 name 的值。
  • key(*index*):取得给定数值位置的名称。
  • removeItem(*name*):删除给定 name 的名/值对。

IndexedDB

IndexedDB 是浏览器中存储结构化数据的一个方案。用于代替目前已废弃的 Web SQL Database API。

它是类似于 MySQL 的数据库。与传统数据库最大的区别在于, IndexedDB 使用 对象存储 而不是表格保存数据。IndexedDB 数据库就是在一个公共命名空间下的一组对象存储,类似于 NoSQL 风格(mongoDB)的实现。

作者在书中详细的介绍了 IndexedDB 的使用,包括:

  1. 如何创建对象存储
  2. 如何开启 事务
  3. 如何插入对象
  4. 如何使用游标查询

这些内容涉及到了很多具体的代码,咱们这里就不去细说了。

感兴趣的同学可以看下书中的介绍。

26:模块

本章的内容主要分为四部分:

  1. 理解模块模式
  2. 凑合的模块系统
  3. 使用前 ES6 模块加载器
  4. 使用 ES6 模块

理解模块模式

所谓模块化其实指的就是:把逻辑分块,各自封装,相互独立,每个块自行决定对外暴露什么,同时自行决定引入执行哪些外部代码

这些不同的模块想要连接在一起工作,那么必须有一个 入口,也就是代码执行的起点。

image-20230723105830655

图中的箭头表示依赖方向:模块 A 依赖模块 B 和模块 C,模块 B 依赖模块 D 和模块 E,模块 C 依赖模块 E。

因为模块必须在依赖加载完成后才能被加载,所以这个应用程序的入口模块 A 必须在应用程序的其他部分加载后才能执行。

凑合的模块系统

所谓 凑合的模块系统 指的是 IIFE(立即调用函数表达式) 的模块化方式:

image-20230723110240135

这种立即执行函数可以通过外部传参的形式传递参数:

image-20230723110457178

使用前 ES6 模块加载器

ES6 之前的模块加载器,指的主要是三部分:

  1. CommonJS
  2. AMD
  3. UMD

咱们这里主要来看下 CommonJS 就可以。

CommonJS 模块语法不能在浏览器中直接运行,主要应用在 node 环境中。

image-20230723110753542

CommonJS 模块定义需要使用 require()指定依赖,而使用 exports 对象定义自己的公共 API

使用 ES6 模块

ES6 模块化咱们在其他的书中讲解过很多次了。这里咱们就不再多说了。给大家把脑图的内容展示即可。

27:工作者线程

工作者线程是一套比较复杂的内容,大致可以分为四个部分:

  1. 工作者线程简介
  2. 使用专用工作者线程执行后台任务
  3. 使用共享的工作者线程
  4. 通过服务工作者线程管理请求

工作者线程简介

JavaScript 环境实际上是运行在托管操作系统中的虚拟环境。

在浏览器中每打开一个页面,就会分配一个它自己的环境。

这样,每个页面都有自己的内存、事件循环、DOM,等等。

每个页面就相当于一个沙盒,不会干扰其他页面。每个页面环境都是 并行执行 的。

而工作者线程的作用就是:让浏览器可以在原始页面环境之外再分配一个完全独立的二级子环境。这个子环境 不能 与依赖单线程交互的 API(如 DOM)互操作,但可以与父环境 并行执行代码。简单来说,就是让 JS 拥有了 类似多线程 的能力。

工作者线程可以分为三类:

  1. 专用工作者线程
  2. 共享工作者线程
  3. 服务工作者线程

这三类工作者线程,作者在书中详细的解释了他们的使用方式。但是因为涉及到的内容比较细节,所以说咱们这里就不去详解了。

28:最佳实践

本书中最后一章的内容,更多的是一些 思想层面 的描述。

内容主要有三部分:

  1. 可维护性
  2. 性能
  3. 部署

可维护性

通常,说代码“可维护”就意味着它具备如下特点:

  • 容易理解:无须求助原始开发者,任何人一看代码就知道它是干什么的,以及它是怎么实现的。
  • 符合常识:代码中的一切都显得顺理成章,无论操作有多么复杂。
  • 容易适配:即使数据发生变化也不用完全重写。
  • 容易扩展:代码架构经过认真设计,支持未来扩展核心功能。
  • 容易调试:出问题时,代码可以给出明确的信息,通过它能直接定位问题。

而想要实现这五点,则需要从 编码规范松散解耦 两个方向入手。

所谓编码规范指的就是:一套规定代码如何编写的方案。这个方案不同的企业可能会有细微差异。

而松散解耦指的就是:不要让代码过于耦合

性能

关于性能的优化,作者主要提出了四个方面:

  1. 作用域意识:访问全局变量始终比访问局部变量慢,因为必须遍历作用域链。任何可以缩短遍历作用域链时间的举措都能提升代码性能
  2. 选择正确的方法:使用最优的计算方法(感觉像废话)。在这里作者介绍了几种方式,比如:简化终止条件、简化循环体、使用后测试循环。但是想要达到这些条件,需要开发者拥有比较好的算法基础。
  3. 语句最少化:语句的数量影响操作执行的速度。一条可以执行多个操作的语句,比多条语句中每个语句执行一个操作要快。
  4. 优化 DOM 交互:涉及 DOM 操作的部分是最慢的,所以想要提升性能则尽量减少 DOM 操作

部署

所谓部署就是把 web 应用程序 发布到线上环境。

整体流程大致分为三步:

  1. 构建:把代码进行打包。可以使用 webpack 等打包工具进行。
  2. 验证:这些错误主要指的是一些 运行时的错误语法错误
  3. 压缩:指的就是代码压缩。比如可以删除一些 空格、换行、注释 的内容。这些内容都会影响最终代码的大小。

总结与下期预告

那么到这里,咱们就把红宝书中的所有内容给看完啦。

其实想要把整本红宝书中的内容全部整理出来,并且压缩到一个小时左右的时间,是一件挺难得事情。

之前全职工作的时候,其实很难有这么多的时间和精力去做这件事情。

这也就导致之前虽然答应了一些小伙伴要录制红宝书,但是一直没有录制出来的原因。

那么现在,这个 flag 可算是完成了。

在下一期,咱们会去讲这一本书《程序员超强大脑》。

它主要讲解了 程序员认知 层面的问题。因为 程序设计本质上是一个认知过程。

如果我们可以理解这种认知过程,那么就可以大幅度提高咱们的工作学习效率。

那么咱们在下一本书中,再见咯~~

最后一章的内容,更多的是一些 思想层面 的描述。

内容主要有三部分:

  1. 可维护性
  2. 性能
  3. 部署

可维护性

通常,说代码“可维护”就意味着它具备如下特点:

  • 容易理解:无须求助原始开发者,任何人一看代码就知道它是干什么的,以及它是怎么实现的。
  • 符合常识:代码中的一切都显得顺理成章,无论操作有多么复杂。
  • 容易适配:即使数据发生变化也不用完全重写。
  • 容易扩展:代码架构经过认真设计,支持未来扩展核心功能。
  • 容易调试:出问题时,代码可以给出明确的信息,通过它能直接定位问题。

而想要实现这五点,则需要从 编码规范松散解耦 两个方向入手。

所谓编码规范指的就是:一套规定代码如何编写的方案。这个方案不同的企业可能会有细微差异。

而松散解耦指的就是:不要让代码过于耦合

性能

关于性能的优化,作者主要提出了四个方面:

  1. 作用域意识:访问全局变量始终比访问局部变量慢,因为必须遍历作用域链。任何可以缩短遍历作用域链时间的举措都能提升代码性能
  2. 选择正确的方法:使用最优的计算方法(感觉像废话)。在这里作者介绍了几种方式,比如:简化终止条件、简化循环体、使用后测试循环。但是想要达到这些条件,需要开发者拥有比较好的算法基础。
  3. 语句最少化:语句的数量影响操作执行的速度。一条可以执行多个操作的语句,比多条语句中每个语句执行一个操作要快。
  4. 优化 DOM 交互:涉及 DOM 操作的部分是最慢的,所以想要提升性能则尽量减少 DOM 操作

部署

所谓部署就是把 web 应用程序 发布到线上环境。

整体流程大致分为三步:

  1. 构建:把代码进行打包。可以使用 webpack 等打包工具进行。
  2. 验证:这些错误主要指的是一些 运行时的错误语法错误
  3. 压缩:指的就是代码压缩。比如可以删除一些 空格、换行、注释 的内容。这些内容都会影响最终代码的大小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值