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实现包括以下三部分。
将JavaScript插入HTML的主要方法是使用元素,有下列8个属性。
使用元素的方式有以下两种。
<script>
function sayHi() {
console.log("Hi!");
}
script>
<script src="example.js">script>
虽然可以直接在HTML文件中嵌入,但通常认为最佳实践是尽可能将JavaScript代码放在外部文件中。理由包括可维护性、缓存、适应未来。
元素一般放在元素中页面内容后面,因为浏览器解析到起始标签时开始渲染页面,用户会感觉页面加载更快了。
除了标签,还有其他方式可以加载脚本。因为 JavaScript 可以使用 DOM API,所以通过
向DOM中动态添加script元素同样可以加载指定的脚本。
let script = document.createElement('script');
script.src = 'gibberish.js';
// 设置为同步加载
script.async = false;
document.head.appendChild(script);
| 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 |
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通过自动内存管理实现内存分配和闲置资源回收。基本思路很简单:确定哪个变量不会再
使用,然后释放它占用的内存。该过程是周期性的。
垃圾回收程序必须跟踪记录哪个变量还会使用,以及哪个变量不会再使用,以便回收内存。在浏览器的发展史上,用到过两种主要的标记策略来标记未使用变量:标记清理和引用计数。
| 数据类型 | 简介 | 转换函数 |
|---|---|---|
| Undefined | 只有一个值undefined。 | - |
| Null | 只有一个值null,表示一个空对象指针。 | - |
| Boolean | 有两个字面值:true和false。 | Boolean() |
| Number | 整数;浮点值(精度最高可达 17 位小数); Infinity, NaN, | Number(), parseInt(), parseFloat() |
| String | 零或多个16位Unicode字符序列。不可变。模板字面量。插值。 | toString(), String() |
| Symbol | 符号是原始值,且符号实例是唯一、不可变的。 | |
| Object | 无序名值对集合。 |
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");
}
最佳实践:函数要么返回值,要么不返回值。只在某个条件下返回值的函数会带来麻烦,尤其是调试时。
function functionName(arg0, arg1,...,argN) {
statements
}
在 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 对象的通用方式。
| 类型 | 实例化 | 属性 | 方法 |
|---|---|---|---|
| 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的内存占用、插入和删除性能更好。