javaScript之什么是JavaScript、HTML中的JavaScript

240 阅读6分钟

以下内容是本人的学习笔记,内容不详细,只是摘取其一部分,如果有错误请提出指正。

一、什么是JavaScript

1995年,JavaScript问世。当时,它的主要用途是代替Perl等服务器端语言处理输入验证。

1.1 JavaScript实现

虽然JavaScript和ECMAScript基本上是同义词,但JavaScript远远不限于 ECMA-262所定义的那样。

完整的JavaScript实现包含以下几个部分:

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

2.png

1.1.1 ECMAScript

ECMAScript,即ECMA-262定义的语言。Web浏览器只是ECMAScript实现可能存在的一种宿主环境(host environment)。宿主环境提供ECMAScript的基准实现和与环境自身交互必需的扩展。扩展(比如DOM)使ECMAScript核心类型和语法,提供特定于环境的额外功能。其他宿主环境还有服务器端JavaScript平台Node.js和即将被淘汰的Adobe Flash。

如果不涉及浏览器的话,ECMA-262到底定义了什么?在基本的层面,它描述这门语言的如下部分:

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

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

JavaScript实现了ECMAScript,而Adobe ActionScript同样也实现了ECMAScript。

1.1.2 DOM

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

<html>
 <head>
 <title>Sample Page</title>
 </head>
 <body>
 <p> Hello World!</p>
 </body>
</html>

通过DOM可以表示为一组分层节点,如下所示:

1.png

由于网景和微软采用不同思路开发DHTML,开 发者写一个HTML页面就可以在任何浏览器中运行的好日子就此终结。为了保持Web跨平台的本性,万维网联盟(W3C,World WideWeb Consortium) 制定了DOM标准。

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

1.2.3 BOM

IE3和Netscape Navigator 3提供了浏览器对象模型(BOM) API,用于 支持访问和操作浏览器的窗口。

它是唯一一个没有相关标准的JavaScript实现。HTML5改 变了这个局面,这个版本的HTML以正式规范的形式涵盖了尽可能多的 BOM特性。

总体来说,BOM主要针对浏览器窗口和子窗口(frame),不过人们通 常会把任何特定于浏览器的扩展都归在BOM的范畴内。比如,下面就 是这样一些扩展:

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

1.4 小结

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

  • ECMAScript:由ECMA-262定义并提供核心功能。
  • 文档对象模型(DOM):提供与网页内容交互的方法和接口。
  • 浏览器对象模型(BOM):提供与浏览器交互的方法和接口。 JavaScript的这三个部分得到了五大Web浏览器(IE、Firefox、Chrome、 Safari和Opera)不同程度的支持。所有浏览器基本上对 ES5(ECMAScript 5)提供了完善的支持,而对ES6(ECMAScript 6,2015年6月发布) 和ES7(ECMAScript 7)的支持度也在不断提升。这些浏览器对DOM的 支持各不相同,但对Level 3的支持日益趋于规范。HTML5中收录的 BOM会因浏览器而异,不过开发者仍然可以假定存在很大一部分公共 特性。

二、HTML中的JavaScript

将JavaScript引入网页,首先要解决它与网页的主导语言HTML的关系问 题。

2.1 <script>元素

将JavaScript插入HTML的主要方法是使用<script>元素。<script>元素有下列8个属性,用到的最多的应该是src指出要执行的代码的外部文件的路径,其余用到的比较少。(可能只是我用得比较少)

使用<script>的方式有两种:通过它直接在网页中嵌入JavaScript代码, 以及通过它在网页中包含外部JavaScript文件。

在使用行内JavaScript代码时,要注意代码中不能出现字符 串</script>。比如,下面的代码会导致浏览器报错:

<script>
 function sayScript() {
 console.log("</script>");
 }
</script>

浏览器解析行内脚本的方式决定了它在看到字符串</script>时,会将 其当成结束的</script>标签。想避免这个问题,只需要转义字符“\” 即 可:

<script>
 function sayScript() {
 console.log("<\/script>");
 }
</script>

另外,使用了src属性的<script>元素不应该再在<script>和</script> 标签中再包含其他JavaScript代码。如果两者都提供的话,则浏览器只会 下载并执行脚本文件,从而忽略行内代码。

<script>元素的src属性可以是一个完整的URL,而且这个URL指向的资源可以跟包含它的HTML页面不在同一个域中。

不管包含的是什么代码,浏览器都会按照<script>在页面中出现的顺序 依次解释它们,前提是它们没有使用defer和async属性。第二个<script>元的代码必须在第一个<script>元素的代码解释完毕才能开始解释,第三个则必须等第二个解释完,以此类推。

2.1.1 标签占位符

把所有JavaScript文件都放在<head>里,也就意味着必须把所有JavaScript代码都下载、解析和解释完成后,才能开始渲染页面(页面在浏览器解析到<body>的起始标签时开始渲染)。

对于需要很多JavaScript的页面,这会导致页面渲染的明显延迟,在此期间浏览器窗口完全空白。为解决这个问题,现代Web应用程序通常将所有JavaScript引用放在<body>元素中的页面内容后面。如下面的例子所示:

<!DOCTYPE html>
<html>
 <head>
 <title>Example HTML Page</title>
 </head>
 <body>
 <!-- 这里是页面内容 -->
 <script src="example1.js"></script>
 <script src="example2.js"></script>
 </body>
</html>

这样一来,页面会在处理JavaScript代码之前完全渲染页面。用户会感觉 页面加载更快了,因为浏览器显示空白页面的时间短了。

2.1.2 推迟执行脚本

HTML 4.01为<script>元素定义了一个叫defer的属性。只对外部脚本文件有效。这个属性表示脚本在执行的时候不会改变页面的结构。也就是说,脚本会被延迟到整个页面都解析完毕后再运行。因此,在<script>元素中设置defer属性, 相当于告诉浏览器立即下载,但延迟执行。

<!DOCTYPE html>
<html>
 <head>
 <title>Example HTML Page</title>
 <script defer src="example1.js"></script>
 <script defer src="example2.js"></script>
 </head>
 <body>
 <!-- 这里是页面内容 -->
 </body>
</html>

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

在实际当中,推迟执行的脚本不一定总会按顺序执行或者在DOMContentLoaded事件之前执行,因此最好只包含一个这样的脚本。

对defer属性的支持是从IE4、Firefox 3.5、Safari 5和Chrome 7开始的。 其他所有浏览器则会忽略这个属性,按照通常的做法来处理脚本。考虑到这一点,还是把要推迟执行的脚本放在页面底部比较好。

2.1.3 异步执行脚本

HTML5为<script>元素定义了async属性。从改变脚本处理方式上 看,async属性与defer类似。当然,它们两者也都只适用于外部脚本, 都会告诉浏览器立即开始下载。不过,与defer不同的是,标记为async 的脚本并不保证能按照它们出现的次序执行,比如:

<!DOCTYPE html>
<html>
 <head>
 <title>Example HTML Page</title>
 <script async src="example1.js"></script>
 <script async src="example2.js"></script>
 </head>
 <body>
 <!-- 这里是页面内容 -->
 </body>
</html>

给脚本添加async属性的目的是告诉浏览器, 不必等脚本下载和执行完后再加载页面,同样也不必等到该异步脚本下 载和执行后再加载其他脚本。正因为如此,异步脚本不应该在加载期间 修改DOM。

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

2.1.4 动态加载脚本

通过向DOM中动态添加script元素同样可以加载指定的脚本。只要创建一个script元素并将其添加到DOM即可。

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

当然,在把HTMLElement元素添加到DOM且执行到这段代码之前不会发 送请求。默认情况下,以这种方式创建的<script>元素是以异步方式加 载的,相当于添加了async属性。

不是所有浏览器都支持async属性。因此,如果要统一动态脚本的加载行为,可以明确将其设置为同步加载:

let script = document.createElement('script');
script.src = 'gibberish.js';
script.async = false;
document.head.appendChild(script);

以这种方式获取的资源对浏览器预加载器是不可见的。这会严重影响它 们在资源获取队列中的优先级。

要想让预加载器知道这些动态请求文件的存在,可以在文档头部显式声明它们:

<link rel="preload" href="gibberish.js">

2.3 <noscript>元素

<noscript>元素,被用于给不支持JavaScript的浏览器 提供替代内容。

<noscript>元素可以包含任何可以出现在<body>中的HTML元素,<script>除外。在下列两种情况下,浏览器将显示包含在<noscript>中的内容:

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

下面有一个例子:

<!DOCTYPE html>
<html>
 <head>
 <title>Example HTML Page</title>
 <script defer="defer" src="example1.js"></script>
 <script defer="defer" src="example2.js"></script>
 </head>
 <body>
 <noscript>
 <p>This page requires a JavaScript-enabled browser.</p>
 </noscript>
 </body>
</html>

这个例子是在脚本不可用时让浏览器显示一段话。如果浏览器支持脚 本,则用户永远不会看到它。

2.4 小结

JavaScript是通过<script>元素插入到HTML页面中的。这个元素可用于 把JavaScript代码嵌入到HTML页面中,跟其他标记混合在一起,也可用 于引入保存在外部文件中的JavaScript。本章的重点可以总结如下。

  • 要包含外部JavaScript文件,必须将src属性设置为要包含文件的URL。文件可以跟网页在同一台服务器上,也可以位于完全不同的域。

  • 所有<script>元素会依照它们在网页中出现的次序被解释。在不使用defer和async属性的情况下,包含在<script>元素中的代码必须严格按次序解释。

  • 对不推迟执行的脚本,浏览器必须解释完位于<script>元素中的代码,然后才能继续渲染页面的剩余部分。为此,通常应该把<script>元素放到页面末尾,介于主内容之后及</body>标签之前。

  • 可以使用defer属性把脚本推迟到文档渲染完毕后再执行。推迟的脚本原则上按照它们被列出的次序执行。

  • 可以使用async属性表示脚本不需要等待其他脚本,同时也不阻塞文档渲染,即异步加载。异步脚本不能保证按照它们在页面中出现的次序执行。

  • 通过使用<noscript>元素,可以指定在浏览器不支持脚本时显示的内容。如果浏览器支持并启用脚本,则<noscript>元素中的任何内容都不会被渲染。