目录
1. 简介
1.1 什么是JavaScript
JavaScript是一门用来与网页交互的脚本语言,包含:①ECMAScript:由 ECMA-262 定义并提供核心功能。②DOM:提供与网页内容交互的方法和接口。③浏览器对象模型(BOM):提供与浏览器交互的方法和接口。
JavaScript 的这三个部分得到了五大Web浏览器(IE、Firefox、Chrome、Safari和Opera)不同程度
的支持。
互联网发展早期就出现了对客户端脚本语言的需求。1995年,网景为Netscape Navigator 2开发了JavaScript。1996年,微软在自家web浏览器IE3的发布中包含名为JScript的JavaScript实现。两个版本JavaScript的出现促进了标准化进程,1997年,欧洲计算机制造商协会( Ecma)的第39技术委员会(TC39)制定ECMA-262,即ECMAScript标准,翌年ISO和IEC也将之采纳为标准。自此以后,各家浏览器均依据ECMAScript来完成自家的具体实现。
虽然JavaScript和ECMAScript基本上是同义词,但JavaScript远远不限于ECMA-262定义。完整的JavaScript实现包括以下三部分。
- ECMAScript:ECMA-262定义的语言,独立于宿主环境的基准实现。包括语法、类型、语句、关键字、保留字、操作符、全局对象。
- DOM(文档对象模型):用于在HTML中使用扩展的XML的API。DOM将整个页面抽象为一组分层节点。 HTML或XML页面的每个组成部分都是一种节点,包含不同的数据。DOM通过创建表示文档的树,让开发者可以方便地控制网页的内容和结构。使用DOM API,可以轻松地删除、添加、替换、修改节点。
- BOM(浏览器对象模型):用于支持访问和操作浏览器的窗口的API。它是唯一没有相关标准的 JavaScript实现。 HTML5以正式规范的形式涵盖了尽可能多的 BOM 特性,BOM的实现细节应该会日趋一致。
1.2 HTML中的JavaScript
将JavaScript插入HTML的主要方法是使用<script>
元素,有下列8个属性。
- async:可选。表示应该立即开始下载脚本,但不能阻止其他页面动作。只对外部脚本文件有效。
- charset:可选。使用src属性指定的代码字符集。
- crossorigin:可选。配置相关请求的CORS设置。默认不使用 CORS。
- defer:可选。表示脚本可以延迟到文档完全被解析和显示之后再执行。 只对外部脚本文件有效。
- integrity:可选。允许比对接收到的资源和指定的加密签名以验证子资源完整性(SRI)。
- language:废弃。
- src:可选。表示包含要执行的代码的外部文件。
- type:可选。代替language,表示代码块中脚本语言的内容类型(MIME)。一般"text/javascript"。
使用<script>
元素的方式有以下两种。
<!-- 1) 通过它直接在网页中嵌入JavaScript代码 -->
<script>
function sayHi() {
console.log("Hi!");
}
</script>
<!-- 2) 通过它在网页中包含外部JavaScript文件-->
<script src="example.js"></script>
虽然可以直接在HTML文件中嵌入,但通常认为最佳实践是尽可能将JavaScript代码放在外部文件中。理由包括可维护性、缓存、适应未来。
<script>
元素一般放在<body>
元素中页面内容后面,因为浏览器解析到<body>
起始标签时开始渲染页面,用户会感觉页面加载更快了。
除了<script>
标签,还有其他方式可以加载脚本。因为 JavaScript 可以使用 DOM API,所以通过
向DOM中动态添加script元素同样可以加载指定的脚本。
let script = document.createElement('script');
script.src = 'gibberish.js';
// 设置为同步加载
script.async = false;
document.head.appendChild(script);
2. 语言基础
2.1 语法和关键字
ECMAScript | 内容或说明 |
---|---|
区分大小写 | - |
标识符 | ①[a-zA-Z_$][a-zA-Z_$0-9]+;②驼峰命名法;③不能是保留字,true,false,null |
注释 | //单行注释;/* */多行注释 |
严格模式 | 在脚本或函数体开头使用"use strict"; |
语句 | 以分号结尾;多条语句可以合并到C语言风格的代码块中; |
关键字 | break, case, catch, class, const, continue, debugger, default, do, delete, else, export, extends, finally, for, function, instanceof, import, in, if, new, return, super, switch, this, throw, try, typeof, var, void, while, with, yield |
未来保留字 | enum; implements, interface, let, package, private, protected, public, static; await |
2.2 变量
1)声明
EcmaScript变量是松散类型的,可以保存任何类型的数据。关键字var
,const
和let
可以声明变量。最佳实践:①不使用var。②const优先, let次之。
关键字 | ES版本 | 声明范围 | 冗余声明 | 其它 |
---|---|---|---|---|
var | 所有版本 | 函数作用域 | 允许 | hoist; |
let | >=ES 6 | 块作用域 | 不允许 | - |
cont | >=ES 6 | 块作用域 | 不允许 | 必须初始化变量值; |
2)值类型
变量可以包含两种不同类型的数据:原始值和引用值。
类型 | 特点 | 动态属性 | 复制 |
---|---|---|---|
primary | 数据,按值访问 | 原始值不能有属性 | 副本 |
reference | 保存在内存中的对象,按引用访问 | 可增删改属性和方法 | 同一对象 |
ECMAScript 中所有函数的参数都是按值传递的。
3)上下文
执行上下文主要有全局上下文、函数上下文等。
上下文中的代码在执行时,会创建变量对象的一个作用域链(scope chain),其决定了各级上下文中的代码在访问变量和函数时的顺序。可以通过try-catch
或with
语句在作用域链前端临时添加一个上下文。
4)垃圾回收
JavaScript通过自动内存管理实现内存分配和闲置资源回收。基本思路很简单:确定哪个变量不会再
使用,然后释放它占用的内存。该过程是周期性的。
垃圾回收程序必须跟踪记录哪个变量还会使用,以及哪个变量不会再使用,以便回收内存。在浏览器的发展史上,用到过两种主要的标记策略来标记未使用变量:标记清理和引用计数。
2.3 数据类型
数据类型 | 简介 | 转换函数 |
---|---|---|
Undefined | 只有一个值undefined 。 | - |
Null | 只有一个值null ,表示一个空对象指针。 | - |
Boolean | 有两个字面值:true 和false 。 | Boolean() |
Number | 整数;浮点值(精度最高可达 17 位小数); Infinity, NaN, | Number(), parseInt(), parseFloat() |
String | 零或多个16位Unicode字符序列。不可变。模板字面量。插值。 | toString(), String() |
Symbol | 符号是原始值,且符号实例是唯一、不可变的。 | |
Object | 无序名值对集合。 |
2.4 操作符
- 一元操作符:递增(++);递减(–);加(+);减(-);
- 位操作符:按位非(~);按位与(&);按位或(|);按位异或(^);左移(<<);右移(>>);无符号右移(>>>);
- 布尔操作符:逻辑非(!);逻辑与(&&);逻辑非(||);
- 乘性操作符:乘法(*);除法(/);取模(%);指数();
- 加性操作符:加法(+);减法(-);关系:>, <, >=, <=;
- 相等操作符:相等(==);全等();
- 条件操作符:``variable = boolean_expression ? true_value : false_value;
- 赋值操作符:等于(=)
- 逗号操作符:逗号(,)
2.5 流控制语句
if-else
语句:最佳实践是使用语句块,即使只有一行代码。
if (i > 25) {
console.log("Greater than 25.");
} else if (i < 0) {
console.log("Less than 0.");
} else {
console.log("Between 0 and 25, inclusive.");
}
do-while
语句:一种后测试循环语句,即循环体中的代码执行后才会对退出条件进行求值。换句
话说,循环体内的代码至少执行一次。
let i = 0;
do {
i += 2;
} while (i < 10);
while
语句:一种先测试循环语句,即先检测退出条件,再执行循环体内的代码。
let i = 0;
while (i < 10) {
i += 2;
}
for
语句:先测试语句,不过增加了进入循环之前的初始化代码,以及循环执行后要执行的表
达式。
let count = 10;
//初始化代码中可以不使用变量声明关键字。推荐使用let声明迭代器变量,以将变量的作用域限定在循环
for (let i = 0; i < count; i++) {
console.log(i);
}
for-in
语句:一种严格的迭代语句,用于枚举对象中的非符号键属性。
//使用for-in循环显示BOM对象window的所有属性
for (const propName in window) {
document.write(propName);
}
for-of
语句:一种严格的迭代语句,用于遍历可迭代对象的元素。
for (const el of [2,4,6,8]) {
document.write(el);
}
标签语句:用于给语句加标签,典型应用场景是嵌套循环。
start: for (let i = 0; i < count; i++) {
console.log(i);
}
//本例中, start是一个标签,可以在后面通过 break 或 continue 语句引用
break
语句用于立即退出循环,强制执行循环后的下一条语句。
continue
语句也用于立即退出循环,但会再次从循环顶部开始执行。
let num = 0;
for (let i = 1; i < 10; i++) {
if (i % 5 == 0) {
break; //continue;
}
num++;
}
console.log(num); // break:4; continue:8;
with
语句:将代码作用域设置为特定的对象。使用场景是针对一个对象反复操作。由于 with 语句影响性能且难于调试其中的代码,通常不推荐在产品代码中使用 with 语句。
switch
语句:条件/分支。
if (i == 25) {
console.log("25");
} else if (i == 35) {
console.log("35");
} else {
console.log("Other");
}
// swith
switch (i) {
case 25:
console.log("25");
break;
case 35:
console.log("35");
break;
default:
console.log("Other");
}
2.6 函数
最佳实践:函数要么返回值,要么不返回值。只在某个条件下返回值的函数会带来麻烦,尤其是调试时。
function functionName(arg0, arg1,...,argN) {
statements
}
3. 引用类型
3.1 基本引用
在 ECMAScript 中,引用类型是把数据和功能组织到一起的结构。引用类型有时也被称为对象定义,因为它们描述了自己的对象应有的属性和方法。
引用类型经常被错误地称作类。虽然 JavaScript 是一门面向对象语言,但ECMAScript 缺少传统的、面向对象编程语言所具备的某些基本结构,包括类和接口。
对象是某个特定引用类型的实例。
内置对象:任何由 ECMAScript 实现提供、与宿主环境无关,并在 ECMAScript 程序开始执行时就存在的对象。
// 通过 new操作符 后跟 一个构造函数 来创建新对象
let now = new Date(); // 创建引用类型 Date 的一个新实例,并将它保存在变量 now 中
let expression = /pattern/flags; //(字面量形式)创建正则表达式
let expression = new RegExp(pattern, flags); //(构造函数)创建正则表达式
ECMAScript 提供了很多这样的原生引用类型?除时间类型Date
外;还有正则类型RegExp
;不同原始值包装类型Boolean
,Number
,String
;
引用类型与原始值包装类型的主要区别在于对象的生命周期。这意味着不能在运行时给原始值添加属性和方法。
类型 | 实例化 | 属性 | 方法 |
---|---|---|---|
Date | - | parse(), UTC(), … | |
RegExp | pattern, flags | global, … | exec(), test(), … |
Boolean | 能自动创建,不建议直接实例化 | - | valueOf(), … |
Number | 能自动创建,不建议直接实例化 | - | toFixed(), isInteger(), … |
String | 能自动创建 | length, | charCodeAt(); normalize(); substring(); indexOf(); startsWith(); trim(); repeat(); @@iterator; match(); search(); split();… |
Global* | 内置对象 | Object, Function, NaN, Data, RegExp, … | ecnodeURI(); eval(); |
Math | 内置对象 | E, LN10, LOG10E, PI, … | min(), max(); ceil(), round(); random(); log(), … |
* ①浏览器将 window 对象实现为 Global 对象的代理。因此,所有全局作用域中声明的变量和函数都变成了 window 的属性。②调用一个简单返回 this 的函数是在任何执行上下文中获取 Global 对象的通用方式。
3.2 集合引用
类型 | 实例化 | 属性 | 方法 |
---|---|---|---|
Object | new; {…}; | 访问:点语法或中括号 | - |
Array | new; […]; from(); of(); | 访问:中括号;length; | isArray(); keys(), values(), entries(); copyWithin(), fill(); push(), pop(); shift(), unshift(); reverse(), sort(); concat(), splice(); indexOf(), find(); filter(), forEach(), map(); reduce(); … |
Map | new; | size; | set(); has(), get(); delete(), clear(); entries(); forEach(); … |
Set | new; | size; | add(); has(); delete(), clear(); keys(), values(), entries(); forEach(); … |
相较Object
:①Map
会维护键值对的插入顺序。②Map
的内存占用、插入和删除性能更好。