JavaScript
JavaScript是一门用来与网页交互的脚本语言。
完整的JavaScript实现包含以下几个部分
- 核心(ECMAScript),由ECMA-262定义并提供核心功能。
- 文档对象模型(DOM),提供与网页内容交互的方法与接口。
- 浏览器对象模型(BOM),提供与浏览器交互的方法与接口。
DOM
文档对象模型(Document Object Model)是一个应用编程接口(API),用于在HTML中使用扩展的XML。
DOM将整个页面抽象为一组分层节点。HTML或XML页面的每个组成部分都是一种节点,包含不同的数据。
DOM通过创建表示文档的树(DOM树),让开发者可以控制网页的内容和结构。使用DOM API可以删除、添加、替换和修改节点。
//DOM并非只能通过JS来访问,而且也确实被其他很多语言实现了。
BOM
浏览器对象模型,用于支持访问和操作浏览器的窗口。使用BOM,开发者可以操控浏览器显示页面之外的部分,比如:
- 弹出新的浏览器窗口的能力。
- 移动、缩放和关闭浏览器窗口的能力。
- navigator对象,提供关于浏览器的详尽信息。
- location对象,提供浏览器加载页面的详尽信息。
- screen对象,提供关于用户屏幕分辨率的详尽信息。
- performance对象,提供浏览器内存占用、导航行为和时间统计的详尽信息。
- 对cookie的支持。
- 其他自定义对象,如XMLHttpRequest
HTML中的JS
HTML中的<script>标签
标签属性
async(可选)
表示应该立即下载脚本,但是不能阻止其他页面动作,比如下载资源或者等待其他脚本加载。仅对外部脚本生效。
defer(可选)
表示在文档解析和显示完成后再执行脚本是没有问题的。仅对外部脚本生效。
charset(可选)
指定的代码字符集,大多数浏览器并不在乎它的值。
src(可选)
表示包含要执行的代码的外部文件。
要包含外部JS文件,必须将该属性设为要包含文件的URL。
文件可以跟网页在同一台服务器上,也可以位于完全不同的域。
crossorigin(可选)
配置相关请求的CORS(跨域资源共享)设置。默认不使用CORS。
integrity(可选)
允许对比接收到的资源和指定的加密签名以验证子资源的完整性(SRI)。如果接收到的资源的签名与这个属性指定的签名不一致,则页面会报错,脚本不会执行。这个属性可以用于确保内容分发网络(CDN,Content Delivery Network)不会提供恶意内容。
type(可选)
表示代码块中脚本语言的内容类型(MIME类型),如果值是 module
则代码块会被当成ES6模块,而且只有在这个时候代码中才能出现 import
和 export
关键字。
标签使用方法
- 通过该标签直接在网页中嵌入JS代码(行内JS代码)
- 通过该标签在网页中引入外部JS代码
使用行内JS代码时,代码中不能出现字符串 </script>
不然浏览器解析的时候会将其当成结束标签(使用转义字符 <\/script>
可以避免这个问题)。
使用 src
属性的 <script>
标签内部不应该再包含其他JS代码。如果两者都提供,则浏览器只会下载并执行脚本文件而忽略掉行内代码。
按照惯例,外部JS文件扩展名是 .js
。但是这不是必须的,因为浏览器并不会检查包含JS文件的扩展名,但是如果不打算使用 .js
扩展名,一定要保证服务器能返回正确的MIME类型。
标签位置
最初,人们常把所有的 <script>
标签放在 <head>
标签内。这样做法的目的是把外部CSS和JS文件都集中放到一起,但是这样也意味着,必须把所有的JS 代码都下载完,解析完,解释完成后才能开始渲染页面 (页面在浏览器解析到 <body>
标签时才开始渲染) ,对于需要很多JS文件的页面,这会导致页面渲染的明显延迟,进而导致白屏问题。为了解决这个问题,现代Web应用通常将所有JS引用放在 <body>
标签中页面元素的后面。
推迟执行脚本
给 <script>
标签定义 defer
属性。
这个属性表示脚本在执行的时候不会改变页面的结构。因此,这个脚本完全可以在整个页面解析完成后再运行。
H5规范要求脚本应该按照它们出现的顺序执行,因此第一个推迟的脚本会在第二个推迟的脚本前面执行,而且两者都会在 DOMContentLoaded
事件之前执行。但是实际是 推迟的脚本不一定总会按顺序执行或者在 DOMContentLoaded
事件前执行。 因此,最好只包含一个这样的脚本。
异步执行脚本
从脚本的处理方式来看, async
属性和 defer
属性类似。两者都只适用于外部脚本,都是告诉浏览器立刻开始下载。
给 <script>
标签定义 async
属性的目的是告诉浏览器,不必等待脚本下载和执行完成后再加载页面,也不必等待该异步脚本下载和执行后再加载其他脚本。正是因为如此,异步脚本不应该在加载期间修改DOM。
异步脚本保证在页面 load
事件前执行,但是可能会在 DOMContentLoaded
事件前后执行。
动态加载脚本
JS可以使用DOM API,通过向DOM中动态添加script元素同样可以加载指定脚本。
let script = document.createElement('script');
script.src = 'example.js';
script.async = false;
document.head.appendChild(script);
默认情况下,该方式创建的 <script>
标签是异步加载的,相当于添加了 async
属性,但是考虑到不是所有浏览器都支持该属性,所以如果要统一动态脚本的加载行为,可以明确将该属性的值设为 false
,变为同步加载。
动态加载方式获取的资源对浏览器的预加载器是不可见的,这会影响到它们在资源队列中的优先级。要想让预加载器知道这些动态请求文件的存在,可以在文档头部显式声明它们。
<link rel="preload" href="example.js">
<noscript> 元素
该元素被用于给不支持JS 的浏览器提供替代内容。
它可以包含任何出现在 <body>
元素中的HTML 元素,<script>
元素除外。
下列两种情况满足其一,浏览器将显示该标签中的内容:
- 浏览器不支持脚本
- 浏览器对脚本的支持被关闭