4.2. javascript
4.2.1. HTML中的JavaScript总结
JavaScript是通过<script>元素插入到HTML页面中的。这个元素可用于把JavaScript代码嵌入到HTML页面中,跟其他标记混合在一起,也可用于引入保存在外部文件中的JavaScript。本章的重点可以总结如下。
要包含外部JavaScript文件,必须将src属性设置为要包含文件的URL。文件可以跟网页在同一台服务器上,也可以位于完全不同的域。
所有<script>元素会依照它们在网页中出现的次序被解释。在不使用defer和async属性的情况下,包含在<script>元素中的代码必须严格按次序解释。
对不推迟执行的脚本,浏览器必须解释完位于<script>元素中的代码,然后才能继续渲染页面的剩余部分。为此,通常应该把<script>元素放到页面末尾,介于主内容之后及</body>标签之前。
可以使用defer属性把脚本推迟到文档渲染完毕后再执行。推迟的脚本原则上按照它们被列出的次序执行。
可以使用async属性表示脚本不需要等待其他脚本,同时也不阻塞文档渲染,即异步加载。异步脚本不能保证按照它们在页面中出现的次序执行。
通过使用<noscript>元素,可以指定在浏览器不支持脚本时显示的内容。如果浏览器支持并启用脚本,则<noscript>元素中的任何内容都不会被渲染。
4.2.1.1. script标签的位置
过去,所有<Script>元素都被放在页面的<head>标签内, 这种做法的主要目的是把外部的CSS和JavaScript文件都集中放到一起。 这就意味着必须把所有JavaScript代码都下载、解析和解释完成后, 才能开始渲染页面(页面在浏览器解析到<body>的起始标签时开始渲染)。 对于需要很多JavaScript的页面,这会导致页面渲染明显延迟,在此期间浏览器窗口完全空白。
为了解决这个问题,现代Web应用程序通常将所有JavaScript引用放在</body>之前。 页面会在处理JavaScript代码之前完全渲染页面。 这样用户会感觉页面加载更快了,因为浏览器显示空白页面的时间短了。
<body>
<!--这里是页面内容-->
<script src="example1.js"></script>
<script src="example2.js"></script>
</body>
4.2.2. 语言基础总结
JavaScript的核心语言特性在ECMA-262中以伪语言ECMAScript的形式来定义。ECMAScript包含所有基本语法、操作符、数据类型和对象,能完成基本的计算任务,但没有提供获得输入和产生输出的机制。理解ECMAScript及其复杂的细节是完全理解浏览器中JavaScript的关键。下面总结一下ECMAScript中的基本元素。
ECMAScript中的基本数据类型包括Undefined、Null、Boolean、Number、String和Symbol。
与其他语言不同,ECMAScript不区分整数和浮点值,只有Number一种数值数据类型。
Object是一种复杂数据类型,它是这门语言中所有对象的基类。
严格模式为这门语言中某些容易出错的部分施加了限制。
ECMAScript提供了C语言和类C语言中常见的很多基本操作符,包括数学操作符、布尔操作符、关系操作符、相等操作符和赋值操作符等。
这门语言中的流控制语句大多是从其他语言中借鉴而来的,比如if语句、for语句和switch语句等。
ECMAScript中的函数与其他语言中的函数不一样。 不需要指定函数的返回值,因为任何函数可以在任何时候返回任何值。 不指定返回值的函数实际上会返回特殊值undefined。
4.2.2.1. 严格模式
使用ECMASript5的严格模式,在脚本开头加上:
"use strict";
4.2.2.2. var、const、let
有三个关键词可用声明变量:var、const和let。
其中,var在ECMAScript的所有版本中都可用使用,而const和let只能在ECMAScript6及更晚的版本中使用。
在不初始化的情况下,定义的变量会保存一个特殊值:undefined。
4.2.2.3. var变量作用域
function test() {
// 这里message变量是在函数内部使用var定义的。
// 调用test()会创建message变量,函数返回时会销毁。
var message = "hi"; //局部变量
}
test();
console.log(message); //出错!
function test() {
// 因为没有使用var定义,因此是一个全局变量,
// 只要调用一次test函数,就会定义这个变量,并且这个变量在函数外部能访问到。
message = "hi"; //全局变量
}
test();
console.log(message); // hi
注意
虽然可用通过省略var操作符定义全局变量,但不推荐这么做。 在局部作用域中定义的全局变量很难维护,也会造成困惑。 这是因为不能一下子断定省略var是不是有意而为之。
在严格模式下,如果想这样给未声明的变量赋值,则会导致抛出ReferenceError。
4.2.2.4. let的作用域
let跟var的作用差不多,但有着非常重要的区别。
最明显的区别是,let声明的范围是块作用域,而var声明的范围是函数作用域。
let与var的另一个重要的区别,就是let声明的变量不会在作用域中被提升。
// name会被提升
console.log(name); // undefined
var name = 'Matt';
// age不会被提升
console.log(age); // ReferenceError: age没有定义
let age = 26;
与var关键字不同,使用let在全局作用域中声明的变量不会成为window对象的属性(var声明的变量则会)。
4.2.2.5. const
const的行为与let基本相同,唯一一个重要区别是用它声明变量时必须同时初始化变量, 且尝试修改const声明的变量会导致运行时错误。
4.2.2.6. 数据类型
Undefined
Null
Boolean
Number
String
Symbol(ECMAScript6新增)
Object,无序名值对的集合。