什么是Javascript
JavaScript 是一种脚本编程语言,它可以在网页上实现复杂的功能,网页展现给你的不再是简单的静态信息,而是实时的内容更新——交互式的地图、2D/3D 动画、滚动播放的视频等等。
JavaScript 的一个常见用途就是通过文档对象API动态修改HTML、CSS。
这也是我们之后的文章将重点介绍的。
HTML引入JavaScript的两种方式
内部JavaScript
<script>
// 在此编写 JavaScript 代码
</script>
用一个 script
标签包裹起来,里面就可以编写JavaScript代码,如下一个简单的HTML页面所示
注意:该标签不能自闭和 <script />
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Apply JavaScript example</title>
<script>
document.addEventListener('DOMContentLoaded', () => {
function createParagraph() {
const para = document.createElement("p");
para.textContent = "你点击了按钮!";
document.body.appendChild(para);
}
const buttons = document.querySelectorAll("button");
for (const button of buttons) {
button.addEventListener("click", createParagraph);
}
})
</script>
</head>
<body>
<button>Click me</button>
</body>
</html>
外部 JavaScript
- 创建一个文件名为
script.js
的文件,扩展名一定要以.js
结尾,这样才能被识别为 JavaScript 代码 - 将
<script>
元素替换成如下的内容:
<script src="script.js" defer></script>
script.js
内容如下:
function createParagraph() {
const para = document.createElement("p");
para.textContent = "你点击了按钮!";
document.body.appendChild(para);
}
const buttons = document.querySelectorAll("button");
for (const button of buttons) {
button.addEventListener("click", createParagraph);
}
- 完整
html
代码如下:
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Apply JavaScript example</title>
<script src="script.js" defer></script>
</head>
<body>
<button>Click me</button>
</body>
</html>
脚本调用策略
当我们的脚本(JavaScript代码)需要操作/调用HTML代码中的某个元素时,可能出现 undefined
的情况,因为可能HTML代码还没解析完成,JavaScript代码就已经开始调用了。
现代的解决方法
在内部 JavaScript 引入方式中,我们编写了这样的代码
document.addEventListener("DOMContentLoaded", () => {
// …
});
这是一个时间监听器,它监听浏览器 DOMContentLoaded
事件,这样做保证了页面加载完成之后,才会触发该事件,避免了错误。
对于外部 JavaScript 引入的方式,我们在 <script>
标签中加上 defer
属性(只有现代浏览器才会生效),该属性告知浏览器当遇到 script
标签时继续解析HTML的内容,这样 JavaScript 代码和 Html 代码会一并加载,但是 JavaScript 代码加载完成之后并不会执行,会等待HTML代码加载完成之后,才开始执行,从而保证了JavaScript调用Html代码中的元素时,不会出现 undefined
的情况。
以前的解决方法
把脚本元素放在文档体的底部(也就是 </body>
标签之前,与之相邻),这样脚本就可以在 HTML 解析完毕后加载了。例如下面就是以前的解决办法。
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Apply JavaScript example</title>
<script src="script.js" defer></script>
</head>
<body>
<button>Click me</button>
<script src="script.js"></script>
</body>
</html>
这样做的弊端是:当JavaScript代码量大时,会带来显著的性能消耗。
除了 defer
属性之外,还要一个 async
属性,注意它不是解决上面的问题,但是它也能改变脚本的调用策略。
defer
和 async
对比
由图可知:
- 正常流程:解析
html
代码 => 遇到JavaScript
代码,停止HTML
代码解析,解析JavaScript
代码,解析完成之后执行JavaScript
代码 => 解析剩余的html
代码 defer
: 解析html
代码 => 遇到JavaScript
代码 ,Html
代码和JavaScript
代码并行解析 => 等待html
代码解析完成之后,才开始执行JavaScript
代码async
: 解析html
代码 => 遇到JavaScript
代码时,html
代码和JavaScript
代码并行解析 =>JavaScript
代码解析完成之后,立即执行,同时Html
代码停止解析 => 解析剩余的html
代码
假设你的页面有如下三个脚本:
<script async src="js/vendor/jquery.js"></script>
<script async src="js/script2.js"></script>
<script async src="js/script3.js"></script>
由于 async
属性是谁先解析完成谁就会执行,这意味着这三个脚本的执行顺序是不确定的
jquery.js
可能在 script2
和 script3
之前或之后调用,如果这样,后两个脚本中依赖 jquery
的函数将产生错误,因为脚本运行时 jquery
尚未加载。
解决这一问题可使用 defer
属性,脚本将按照出现的顺序加载和运行
<script defer src="js/vendor/jquery.js"></script>
<script defer src="js/script2.js"></script>
<script defer src="js/script3.js"></script>