【JavaScript】- 红宝书(一二)

378 阅读11分钟

引言

历经两个多月断断续续地读完了JavaScript的经典书籍红宝书 -《JavaScript高级程序设计(第4版)

详细地读完一遍后发觉整本书知识点全而泛,乍一想每一章的细节,还是略显模糊。

于是督促自己计划编写每一章的着重点再次加深印象和理解,顺便记录自己的所学所想所悟。方便自身利用电脑的快速搜索关键词来进行快速定位和学习,也希望能帮助到有需要的同学们哈。

若是想要系统仔细的学习,当然还是看原书比较好,我也是强烈推荐的噢!这里内容只当个人复习和总结。

提示: 一些个人主观认为不重要或不流行的章节将进行删减

1. 什么是 JavaScript

1995年问世,其目的是为了实现在客户端即可处理某些基本的验证。

JavaScript已被公认为主流的变成语言,能够实现复杂的计算与交互,包括闭包、匿名函数,甚至元编程等特性。

从简单的出入验证脚本到强大的变成语言,因此这一章就是为了真正学好用好JavaScript来理解其本质、历史及局限性。

1.1 简短的历史回顾

1995年,网景一位名叫 Brendan Eich 的工程师开发叫 Mocha(后来改名为LiveScript) 的脚本语言,在服务器端叫 LiveWire。

网景将 LiveScript 改名为 JavaScript(搭上当时Java的顺风车)。

1996年,由于 JavaScript1.0 的成功,IE开发了JScript。以至于当时出现两个版本的 JavaScript(Navigator 中的 JavaScript 和 IE 中的 JScript)

1997年,欧洲计算机制造商协会(Ecma)为了标准化一门通用、跨平台、厂商而打造出 ECMAScript 这个新的脚本语言标准。

1998年,ISO 和 IEC 两大组织也将 ECMAScript 采纳为标准,至此各大浏览器均以 ECMAScript 作为自己 JavaScript 实现的依据

1.2 JavaScript 实现

JavaScript包括

  • 核心(ECMAScript)
  • 文档对象模型(DOM)
  • 浏览器对象模型(BOM)

1.2.1 ECMAScript

ECMAScript 即 ECMA-262 定义的语言,Web 浏览器只是 ECMAScript 实现可能存在的一种宿主环境

在基本的层面,它描述这门语言的如下部分:

  • 语法
  • 类型
  • 语句
  • 关键字
  • 保留字
  • 操作符
  • 全局对象

总的来说 ECMAScript 只是对实现这个规范描述的所有方面的一门语言的称呼

1.2.2 DOM

**文档对象模型(DOM,Document Object Model)**是一个应用编程接口(API),用于在 HTML 中使用扩展的 XML。DOM将整个页面抽象为一组分层节点。HTML 或 XML 页面的每个组成部分都是一种节点,包含不同数据。

开发者可以使用 DOM API 来轻松地删除、添加、替换、修改节点。

1.2.2.1 DOM 是必须的

为了保持 Web 跨平台的本性,万维网(W3C,World Wide Web Consortium)开始了制定 DOM 标准。

注意: DOM 并非只能通过 JavaScript 访问,而且确实被其他很多语言实现了。不过对于浏览器来说,DOM 就是使用 ECMAScript 实现的,如何已经成为 JavaScript 语言的一大组成部分

  • DOM Level 1
    • DOM Core: 映射XML文档,从而方便访问和操作文档任意部分的方式。
    • DOM HTML: 扩展前者,并增加了特定于HTML的对象和方法。
  • DOM Level 2
    • DOM 视图: 描述追踪文档不同视图(如应用CSS样式前后的文档)的接口。
    • DOM 事件: 描述事件及事件处理的接口。
    • DOM 样式: 描述处理元素 CSS 样式的接口。
    • DOM 遍历和范围: 描述遍历和操作 DOM 树的接口。
  • DOM Level 3
    • DOM Load and Save: 以统一的方式加载和保存文档的方法。
    • DOM Validation: 验证文档的方法。
    • DOM Core扩展: 支持了所有 XML 1.0的特性,包括 XML Infoset、XPath 和 XML Base。
  • DOM4: W3C不再按照 Level 来维护 DOM 了,而是作用 DOM Living Standard 来维护,其快照称为 DOM4。
    • Mutation Observers: 替代 Mutation Events。

注意: 并没有一个标准叫 DOM Level 0,这只是 DOM 历史中的一个参照点。可以看作 IE4 和 Netscape Navigator 4 中最初支持的 DHTML。

1.2.3 BOM

**BOM(浏览器对象模型)**用于支持访问和操作浏览器的窗口,开发者可以实现操作浏览器显示页面之外的部分。

总的来说,BOM 主要针对浏览器窗口和子窗口(frame)不过人们通常会把特定于浏览器的扩展都归在 BOM 的范畴内。

  • 弹出新浏览器窗口的能力。
  • 移动、缩放和关闭浏览器窗口的能力。
  • navigator 对象,提供关于浏览器的详尽信息。
  • location 对象,提供浏览器加载页面的详尽信息。
  • screen 对象,提供关于铜壶屏幕分辨率的详尽信息。
  • performance 对象,提供浏览器内存占用、导航行为和时间统计的详尽信息。
  • 对 cookie 的支持。
  • 其他自定义对象,如 XMLHttpRequest 和 IE 的 ActiveXObject。

因为 BOM 很多时间内都没有标准,每个浏览器实现的都是自己的 BOM 定义了自己的属性和方法。不过现在有了 HTML5,BOM 的实现细节应该会日趋一致。关于 BOM,后边的章节和详细接招。

1.3 总结

JavaScript 是一门用来与网页交互的脚本语言,包含以下三个部分。

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

JavaScript 的这三个部分得到了五大 Web 浏览器(IE、Firefox、Chrome、Safari 和 Opera)不同程度的支持。HTML5 中收录的 BOM 也会因浏览器而异。

2. HTML 中的 JavaScript

将 JavaScript 引入网页,首先要解决它与网页的主导语言 HTML 的关系问题。也就是引入的同时,不会导致页面在其他浏览器中渲染出问题。

2.1 <script> 元素

早期将 JavaScript 插入 HTML 的主要方法是使用 <script> 元素。这个元素是由网景公司创造出来,并最早在 Netscape Navigator 2 中实现。后来,被正式加入到 HTML 规范。 <script> 有下列8个属性

  • async: 可选。表示应该立即开始下载脚本,但不能阻止其他网页动作,比如下载资源或等待其他脚本加载。只对外部脚本文件有效。
  • charset: 可选。使用 src 属性指定的代码字符集。
  • crossorigin: 可选。配置相关请求的 CORS(跨源资源共享)设置,默认不使用。
  • defer: 可选。表示在文档解析和显示完成后再执行脚本,只对外部脚本有效(在 IE7 及更早版本中,对行内脚本也可指定)。
  • integrity: 可选。允许比对接收到的资源和指定的加密签名以验证子资源的完整性,如果接收到的资源的签名与这个属性指定的签名不匹配,则页面会报错,脚本不会执行。这个属性可以用于确保内容分发网络(CDN)不会提供恶意内容。
  • src: 可选。表示包含要执行的代码的外部文件。
  • type: 可选。替代language,表示代码块中脚本语言的内容类型(也称 MIME 类型)。通常为 "application/x-javascript",如果该值为 module,则代码会被当成 ES6 模块,而且只有在这个时候代码中才能出现 import 和 export 关键字。
  • language: 废弃。

使用 <script> 的方式有两种:

  • 嵌入行内 JavaScript 代码,直接把代码放在 <script> 元素中就行:

    • <script>
        function sayHi() {
          console.log('Hi!');
        }
      </script>
      
  • 引入外部文件中的 JavaScript 文件

    • <script src="example.js"></script>
      
      • 在 XHTML 文档中,可以忽略结束标签,但在 HTML 文件中不能使用

要避免同时使用两种方式,若两者都提供的话,则浏览器只会下载并执行脚本文件,从而忽略行内代码。

不管包含的是什么代码,浏览器都会按照 <script> 在页面中出现的顺序依次解释它们,前提是它们没有使用 defer 和 async 属性。

2.1.1 标签位置

过去,所有 <script> 元素都被放在页面的 <head> 标签内。这种做法主要是将外部的 CSS 和 JavaScript 文件都集中放到一起。但问题是将导致页面必须把 <head> 中的所有外部文件下载、解析和解释完成后,才能开始渲染页面(页面在浏览器解析到 <body> 的起始标签时开始渲染)。因此现代 Web 应用程序通常将**所有 JavaScript 引用放在 <body> 元素中的页面内容后面。**这样一来,用户会感觉页面加载更快了,因为浏览器显示空白页面的时间短了。

2.1.2 推迟执行脚本

在 <script> 元素上设置 defer 属性,会告诉浏览器应该立即开始下载(同步),但执行应该推迟,如下列的代码块:

<head>
	<script defer src="example1.js"></script>
	<script defer src="example2.js"></script>
</head>

虽然 <script> 元素包含在页面的 <head> 中,但它们会在浏览器解析到结束 </html> 标签后才会执行。

defer 属性只对外部脚本文件才有效,在高浏览器版本中会忽略行内脚本的 defer 属性。

将要推迟执行的脚本放在页面的底部会比较好。

对于 XHTML 文档,执行 defer 属性时应该写成 defer="defer"。

2.1.3 异步执行脚本

async 属性与 defer 属性类似,两者都只适用于外部脚本,都会告诉浏览器立即开始下载。不过 async 是异步下载(不能保证次序执行)

<head>
	<script defer src="example1.js"></script>
	<script defer src="example2.js"></script>
</head>

async 异步脚本保证会在页面的 load 事件前执行,但可能会在 DOMContentLoaded(参见第17章)之前或之后。

使用 async 会告诉页面你不会使用 document.write,不过好的 Web 开发实践根本就不推荐使用这个方法。

对于 XHTML 文档,执行 defer 属性时应该写成 async="async"。

2.1.4 动态加载脚本

通过 DOM API 来向 DOM 中动态添加 script 元素同样可以加载指定的脚本。

let script = document.createElement('script')
script.src = 'example1.js'
document.head.appendChild(script)

以这种方式创建的 <script> 元素是以异步方式加载的,相当于添加了 async 属性。可以通过属性 async = false 进行设置为同步加载。

2.2 行内代码与外部文件

虽然可以直接在 HTML 文件中嵌入 JavaScript 代码,但通常认为最佳实践是尽可能将 JavaScript 代码放在外部文件中。推荐理由如下:

  • 可维护性。JavaScript 文件统一保存代码,更容易维护,这样开发者就可以独立于使用它们的 HTML 页面来编辑代码。
  • 缓存。浏览器会根据特定的设置缓存所有外部链接的 JavaScript 文件,这意味着多次使用该同一文件,则该文件只需加载一次。
  • 适应未来。通过把 JavaScript 放在外部文件中,就不必考虑用 XHTML 或注释黑科技来解决兼容问题。

在 SPDY/HTTP2 中,预请求的消耗已显著降低,以轻量、独立 JavaScript 组件形式向客户端送达脚本更具优势。

原因是浏览器会缓存已下载的轻量、独立 JavaScript 文件。

2.4 <noscript> 元素

<noscript> 元素,针对早期浏览器不支持 JavaScript 的问题。虽然如今的浏览器已经近乎 100% 支持 JavaScript,但对于禁用 JavaScript 的浏览器来说,这个元素仍然有它的用处。

  • <noscript> 元素一般放在 <body> 元素中,可以包含任何出现在 <body> 中的 HTML 元素, <script> 除外。
  • 当下列任意两种情况发送时, <noscript> 元素将发挥作用。否则浏览器将不会渲染 <noscript> 元素。
    • 浏览器不支持脚本。
    • 浏览器对脚本的支持被关闭。

下列是代码🌰片段

<body>
  <noscript>
  	<p>This page requires a JavaScript-enabled browser.</p>
  </noscript>
</body>

若该浏览器脚本不可使用,用户将得到提示,否则用户永远不会看到它。

2.5 总结

  • 要包含外部 JavaScript 文件,必须将 src 属性设置为文件的 URL。文件可以跟网页在用一台服务器上,也可以位于完全不同域。
  • 在不使用 defer 和 async 属性的情况下,所有 <script> 元素会依照它们在网页中出现的次序被解释。
  • 对正常脚本而言,为提升用户感受(让页面渲染更快)。应该把 <script> 元素放到页面末尾( </body> 标签前一行)
  • 可以使用 defer 属性把脚本推迟到文档渲染完毕后再执行,按次序执行。
  • 可以使用 async 属性表示脚本不需要等待其他脚本,同时也不阻塞文档渲染,即异步加载,不能保证按次序执行。
  • 通过使用 <noscript> 可以进行提示该浏览器是否执行并启用脚本。