旧游无处不堪寻
无寻处,惟有少年心
JavaScript(一)

之前的几篇,我们介绍了 HTML 和 CSS 基础知识,对于网页结构和样式,都有了一定的了解。从这篇之后,我们将介绍网页中另一个重要知识 - JavaScript。我们将参考《JavaScript 高级程序设计》,对每章的重要知识进行详细的讲解。

JavaScript 简介


JavaScript 堪称世界上被人误解最深的编程语言,常被嘲为”玩具语言”,但在它看似简洁的外衣下,还隐藏着强大的语言特性。JavaScript 目前广泛应用于众多知名应用中,对于网页和移动开发者来说,深入理解 JavaScript 就尤有必要。

什么是 JavaScript?

JavaScript 最初的目的是为了”让网页动起来”。
这种编程语言我们称之为脚本。它们可以写在 HTML 中,在页面加载的时候会自动执行。脚本作为纯文本存在和执行。它们不需要特殊的准备或编译即可运行。

JavaScript 在刚诞生的时候,它的名字叫”LiveScript”。但是因为当时 Java 很流行,所以决定将一种新语言定位为 Java 的”弟弟”会有所帮助。随着 JavaScript 的发展,它已经变成了一门独立的语言,同时也有了自己的语言规范 ECMAScript。现在,它和 Java 之间没有任何关系。

一个完整的 JavaScript 实现应由三个不同部分组成:

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

ECMASCript

ECMAScript 与 Web 浏览器没有依赖关系。我们常见的 Web 浏览器只是 ECMAScript 的宿主环境之一。
宿主环境会提供 ECMAScript 的基本实现以及该语言的扩展,以便语言与宿主对接交互。如: DOM 就是浏览器宿主对 ECMAScript 语言实现的扩展。
我们知道的 Node 就是 ECMAScript 在服务器端的宿主环境。
ECMAScript 规定了:

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

BOM

BOM(Browser Object Model)是 JavaScript 提供给我们来操纵浏览器的手段。如: 我们可以使用 BOM 调整浏览器的窗口高度、宽度、位置等。在 HTML5 中被纳入标准。

DOM

简单来说,DOM(Document Object Model)是一套对文档内容进行抽象和概念化的方法。
最早的 DOM 未成标准,各个浏览器的实现都不同,在实际工作中,很多脚本不得不编写多次。在 1998 年 10 月,完成了 DOM Level 1。标准化的 DOM 可以让任何一种编程语言对使用任何一种标记语言编写的任何一份文档进行操控。

W3C 的 DOM 定义: 一个与系统平台和编程语言无关的接口,程序和脚本可以通过这个接口动态的访问和修改文档的结构,内容和样式。

请注意: DOM 并不只针对 JavaScript 的。

DOM1 由 2 个模块组成:

  • DOM 核心(DOM Core)
  • DOM HTML

DOM 核心规定了如何映射基于 XML 的文档结构,DOM HTML 则在 DOM 核心基础上加以扩展,添加了针对 HTML 的对象和方法。

DOM2 引入了下列新模块:

  • DOM View: 定义了跟踪不同文档视图的接口
  • DOM Events: 定义了事件和事件处理接口
  • DOM Style: 基于 CSS 为元素应用样式的接口
  • DOM Traversal and Range: 定义了遍历和操作文档树的接口

DOM3 进一步扩展 DOM:

  • DOM Load and Save: 定义了统一加载和保存文档的接口
  • DOM Validation: 验证文档接口

内核和引擎

我们知道,浏览器内核包括:

  • 渲染引擎
  • JS 引擎

常见的渲染引擎有: blank、webcore 等,常见的 JS 引擎有: jscore、chakra、V8 等。

引擎很复杂,但是基本原理很简单:

  1. 引擎(通常嵌入在浏览器中)读取(解析)脚本
  2. 然后将脚本转化(编译)为机器语言
  3. 然后就可以在机器上飞速的运行

引擎会对流程中的每个阶段都进行优化。它甚至可以在运行时监视编译的脚本,分析数据流并根据这些对机器代码应用优化。最后,脚本会执行地非常快。

浏览器中的 JavaScript 能做什么 ?

浏览器中的 JavaScript 可以完成下面这些事:

  • 在网页中插入新的 HTML,修改现有的网页内容和网页的样式
  • 响应用户的行为,响应鼠标的点击或移动、键盘的敲击
  • 向远程服务器发送请求,使用 AJAX 和 COMET 技术下载或上传文件
  • 获取或修改 cookie,向用访问者提出问题、发送消息
  • 记住客户端的数据(本地存储)

浏览器中的 JavaScript 不能做什么?

  • 网页中的 JavaScript 不能读写、复制及执行用户磁盘上的文件或程序。它没有直接访问操作系统的功能
  • 不同的浏览器标签页之间基本彼此不相关
  • JavaScript 通过互联网可以很容易的和服务器(当前网页域名的服务器)通讯。但是从其他的服务器中获取数据的功能是受限的,需要服务器(在 HTTP 头中)添加某些参数

其他语言

最近出现了很多不同的语言,这些语言在浏览器中执行之前,都会被编译(转化)成 JavaScript。
现代化的工具使得编译速度非常快速和透明,实际上允许开发人员使用另一种语言编写代码并将其自动转换为 JavaScript。

这些语言的例子有:

  • CoffeeScript: 是 JavaScript 的语法糖,它语法简短,明确简洁。通常使用 Ruby 的人喜欢用
  • TypeScript: 将注意力集中在增加严格的数据类型。这样就能简化开发,也能用于开发复杂的系统。TypeScript 是微软开发的
  • Dart 是一门独立的语言。它拥有自己的引擎用于在非浏览器环境中运行(如: 在手机应用中运行)。最开始是 Google 提供的用于替代 JavaScript 的,但是现在,它和其他上述的语言一样,浏览器也要求它被编译成 JavaScript

在 HTML 中使用 JavaScript


向 HTML 页面插入 JavaScript 的主要方法,就是使用 script 元素。其定义了4个属性:

  • async: 表示立即下载脚本,但不应妨碍页面的其他操作,如下载其他资源或等待加载其他脚本。只对外部脚本有效
  • defer: 表示脚本可以延迟到文档完全被解析和显示之后再执行。只对外部脚本有效
  • src: 表示包含要执行代码的外部文件
  • type: 默认是 text/javascript,一般不写

使用 script 元素的方式有两种:

  • 直接在页面嵌入 JS 代码
  • 包含外部 JS 文件

注意: 在使用嵌入代码时,不要在代码中出现 “</script>” 字符串。使用转义解决这个问题。
当使用嵌入代码时,解释器对 script 元素内部的所有代码求值完毕前,页面的其余内容都不会被浏览器加载显示。
当使用外部文件时,页面的处理也会暂时停止。
也就是说,无论如何使用 script 元素,只要不存在 async 或者 defer 属性,浏览器都会按照 script 元素在页面出现的先后顺序对他们依次解析,即只有第一个 script 元素中的所有代码解析完毕,才会开始解析下一个。

script 元素的位置

为了避免出现上述所说的阻塞问题,现代 Web 应用一般把 JavaScript 引用放到 body 结束标记之前。

defer 属性

该属性表示: 立即下载,延迟执行。并且 HTML5 要求脚本按照出现的先后顺序,在其他同步脚本执行后,DOMContentLoaded 事件前依次执行,因此第一个延迟脚本会先于第二个延迟脚本执行。最佳实践是只有一个延迟脚本。

async 属性

与 defer 一样,都用于改变脚本的加载行为,都是告诉浏览器立即下载,但是与 defer 不同的是: 标记为 async 属性的脚本不能保证执行顺序。因此确保脚本之间互不依赖非常重要。
异步脚本一定会在 load 事件之前执行,可能会在 DOMContentLoaded 事件之前或之后执行。

defer 与 async 比较

  • 两者都不会阻止 document 的解析
  • defer 会在 DOMContentLoaded 前依次执行 (可以利用这两点哦!)
  • async 则是下载完立即执行,不一定是在 DOMContentLoaded 前
  • async 因为顺序无关,所以很适合像 Google Analytics 这样的无依赖脚本

嵌入代码和外部文件

我们应尽量使用外部文件,因为:

  • 可维护性
  • 可缓存
  • 适应未来

noscript 元素

noscript 元素的内容只有在下面两种情况才显示:

  • 浏览器不支持脚本
  • 浏览器支持脚本,但脚本被禁用

除此之外,浏览器都不会显示 noscript 元素中的内容。