红宝书学习笔记【第1~2章】

67 阅读6分钟

总感觉一直在看各种零散的JS文章,但很多知识不成体系,容易忘却,加上前段时间面试,不停被基础问题打个措手不及,所以想自己看书整理一下这些知识。 以下只是一个菜鸟的学习笔记,算不上什么技术交流,如果有理解和表达错误的点或者冗余废话,还请原谅,欢迎指正和建议。

红宝书学习笔记【第1~2章】

第一章

基本都是js的发展历史,和js的宏观概念

为什么需要js

js出现之前,表单信息得通过服务端校验,但那时网络的速度还很慢,用户的体验极差,所以“网景”公司决定开发一个客户端的脚本语言来处理处理简单的数据验证。

js的实现

完整的js包含: 核心(ECMAScript):由ECMA-262 定义并提供核心技能 文档对象模型(DOM):提供与网页内容交互的方法和接口 浏览器对象模型(BOM):提供与浏览器交互的方法和接口

第二章 HTML 中的 JavaScript

<script> 元素

1. 可选属性

  1. async: 表示立即异步下载脚本, 不阻止其他页面动作, 比如下载资源或等待其他脚本加载. 只对外部脚本有效.

  2. defer: 表示脚本可以延迟到文档完全被解析和现实后再执行, 只对外部脚本文件有效.

  3. src: 表示包含要执行的外部代码文件

  4. charset: 使用src属性指定的代码字符集, 大多数浏览器不在乎它的值.

  5. crossorigin: 配置相关请求的CORS设置.

  6. integrity:允许比对接收到的资源和指定的加密签名以验证子资源完整性

  7. language: 废弃, 用于表示代码块中的脚本语言(如"JavaScript", "VBScript"). 大多数浏览器会忽略该属性.

  8. type: 代替language, 表示代码块中的脚本语言内容类型(MIME). 常用来设置为"module", 让代码被当做es6模块, 从而允许代码中使用importexport关键字.

2. 使用方式

  1. 通过它直接在网页中嵌入js代码(行内方式)
  2. 通过它在网页中包含其他外部js文件(外链方式)

注意事项:

  1. 不论哪种方式, 在解释js代码时都会阻塞页面(阻塞时间包含下载文件的时间).
  2. 按照惯例, 外部js文件的扩展名应该是.js, 但浏览器不会检查所包含js文件的扩展名, 所以扩展名不是必须的. 这为服务器端动态生成js代码和在浏览器中将ts和jsx等扩展语言转为js提供了可能性. 需要注意, 服务器端会根据文件扩展名来确定响应的正确MIME类型.
  3. 使用了src属性的script标签中不应该再包含行内的js代码. 该情况下浏览器会加载外部文件, 忽略行内js代码.

3. <script>和浏览器跨域

<img>元素相似, <script>的src可以是完整的url地址, 而且该url可以指向与当前网页不在同一域下的资源.

浏览器解析该资源时, 会向 src 属性指定的路径发出 GET 请求(该请求受网页的 HTTP/HTTPS 协议的限制), 已取得文件资源. 该请求不受浏览器同源策略的制约, 但加载并执行的js代码会受到限制.

因为外部文件可能被程序员恶意替换, 所以这种方式并不安全, <script>标签的 integrity 属性是防范这种问题的一个武器,但这个属性也不是所有浏览器都支持。

4. <script>的加载和执行时机

一般情况

默认情况下, 浏览器按照<script>出现顺序依次解释它们, 第二个<script>必须在第一个<script>解析完毕才能开始解释.

过去, 所有<script>都被放在<head>标签中, 目的是将外部的css和js都集中放在一起. 但这种做法意味着所有js代码都加载,解析和执行后, 才开始渲染页面 ( 浏览器解析到<body>标签时开始渲染 ). 这导致页面渲染被推迟,白屏时间增加. 现在, 通常将<script>标签都放在<body>标签的最后.

推迟(defer) 和 异步(async)

1. defer

该属性只对外部脚本文件有效.

该属性表示, 脚本在执行时不会改变页面结构, 将脚本延迟到整个页面解析结束( 浏览器解析到<\html> )再运行.

理论上, 被延迟的多个脚本会按照<script>标签的顺序执行, 被延迟执行的脚本会在 DOMContentLoaded事件之前执行, 但实际上被延迟的脚本不一定会按顺序执行, 也不一定都在DOMContentLoaded事件之前执行, 所以最好只包含一个这样的脚本.

2. async

该属性与defer类似, 都只适用于外部脚本文件, 都不能改变页面结构, 都会让浏览器立即开始下载文件(异步), 但标记为async的脚本不保证按照出现顺序执行, 而是在加载结束后执行.

async标记的脚本在下载和执行时, 不阻塞页面的加载, 也不影响其他js脚本的加载.

异步脚本保证会在页面的 load 事件前执行,但可能会在 DOMContentLoaded之前或之后。

3. defer 和 async 的不同点
  1. 出现时间不同, defer是HTML4.01 出现的, async是在HTML5.
  2. 执行时间不同, defer的脚本会在页面解析结束后执行, async的脚本会在脚本加载结束后执行.
  3. defer理论上按照<script>标签出现的顺序执行, async不按照出现顺序执行.

动态加载脚本

我们可以通过 DOM API, 通过创建<script>标签动态加载脚本.

在没有将<script>标签加入到页面之前, 该脚本不会被加载. 而且该方式默认以 async 方式加载脚本. 但并不是所有浏览器都支持 async 属性, 所以为了统一脚本的加载行为, 可以在创建<script>标签时, 设置其 async 属性为 false.

以这种方式加载资源时, 对浏览器的预加载器不可见, 这会严重影响它们在资源加载队列的优先级. 所以可以在文档头部显式声明他们:

<link ref="preload" href="example.js">

<noscript>

<noscript>元素可以包含任何可以出现在<body>中的 HTML 元素,<script>除外。

在下列两种情况下,浏览器将显示包含在<noscript>中的内容:

  • 浏览器不支持脚本;
  • 浏览器对脚本的支持被关闭。

任何一个条件被满足,包含在<noscript>中的内容就会被渲染。