JavaScript-高级程序设计-Notes

第1章 什么是 JavaScript

1.2 JavaScript 实现

JavaScript 和 ECMAScript 基本上是同义词.

包括的部分:

1.2.1 ECMAScript

ECMAScript 是 ECMA-262 定义的语言,并不局限于 Web 浏览器. 这门语言没有输入和输出之类的方法.

ECMAScript 只是对实现这个规范描述的所有方面的一门语言的称呼. 规范包括:

1.2.2 DOM

DOM 是 Document Object Model,文档对象模型的简称. 是一个应用编程接口 (API), 用于在 HTML 中使用扩展的 XML.

DOM 通过创建表示文档的树,让开发者可以随心所欲控制网页的内容和结构:

DOM 并非只能通过 JavaScript 访问, 其他很多语言都实现了.

支持 DOM 对浏览器厂商极为重要.

1.2.3 BOM

BOM 是 Browser Object Model 的缩写. 也是一个 API, 用于支持访问和操作浏览器的窗口.

JavaScript 版本

第2章 HTML 中的 JavaScript

<script> 元素

<script> 元素有八个属性:

两种使用 <script> 的方法:

  • 将代码放在 <script> 元素中 (在 <script> 元素中的代码被计算完成之前,页面的其他内容不会被加载,也不会被显示)
  • 使用 src 属性来包含外部文件中的 JavaScript
    如:
    1
    <script src="example.js"></script>

注意,外部 JavaScript 文件的扩展名是 .js, 这是不需要的,因为浏览器不会检查所包含 JavaScript 文件的扩展名.

使用了 src 属性的 <script> 元素不应该再在 <script></script> 标签中再包含其他 JavaScript 代码,不然行内代码会被忽略.

2.11 标签位置

现代 Web 应用程序通常将所有 JavaScript 引用放在 <body> 元素中页面内容后面:

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<title>Example HTML Page</title>
</head>
<body>
...
<script src="example1.js"></script>
<script src="example2.js"></script>
</body>
</html>

2.1.2 推迟执行脚本

放在页面底部比较好. defer 属性可能会被忽略.

2.1.3 异步执行脚本

async 属性和 defer 类似. 两者都只适用于外部脚本.

标记为 async 的脚本并不能保证能按照它们出现的次序执行.

async 属性告诉浏览器,不必等脚本下载和执行完后再加载页面, 同样也不必等到该异步脚本下载和执行后在加载其他脚本.

2.1.4 动态加载脚本

向 DOM 中动态添加 script 元素同样可以加载指定的脚本.

2.1.5 XHTML 中的变化

XHTML, Extensible HyperText Markup Language,可扩展超文本标记语言是将 HTML 作为 XML 的应用重新包装的结果.

在 XHTML 中使用 JavaScript 必须指定 type 属性且值为 text/javascript.

2.1.6 废弃的语法

2.2 行内代码与外部文件

通常认为最佳实践是尽可能将 JavaScript 代码放到外部文件中.

2.3 文档模式

使用 doctype 切换文档模式.

三种文档模式:

  • 混杂模式 (quirks mode)
  • 标准模式 (standards mode)
  • 准标准模式 (almost standards mode)

2.4 <noscript> 元素

第3章 语言基础

3.1 语法

3.1.1 区分大小写

3.1.2 标识符

3.1.3 注释

C 语言的注释.

3.1.4 严格模式

是一种解析和执行模型,将不规范写法抛出.

对整个脚本启用严格模式,在脚本开头加上一行:

1
"use strict";

其为一条预处理指令.

也可以单独指定一个函数在严格模式下执行:

1
2
3
4
function doSomething() {
"use strict";
...
}

3.1.5 语句

以分号结尾.

if 语句和 C 一样.

3.2 关键字和保留字

3.3 变量

有三个关键字可以声明变量: var, constlet.

3.3.1 var 关键字

不初始化的情况下,变量会保存一个特殊值 undefined.

1. var 声明作用域

使用 var 操作符定义的变量会成为包含它的函数的局部变量.

省略 var 操作符定义全局变量,但不推荐这么做.

定义多个变量可以这样写:

1
2
3
var message = "hi",
found = false,
age = 29;

2. var 声明提升

1
2
3
4
5
function foo() {
console.log(age);
var age = 26;
}
foo();

等价于:

1
2
3
4
5
6
function foo() {
var age;
console.log(age);
age = 26;
}
foo();

因此,反复声明也不会报错.

3.3.2 let 声明

let 声明的范围是块作用域, 而 var 声明的范围是函数作用域.

块作用域可以看作是函数作用域的子集.

let 不能重复声明.

1. 暂时性死区

let 不会在作用域中被提升.

4. for 循环中的 let 声明

for 循环的语法同样和 C 中相同.

let 出现之前,for 循环定义的迭代变量会渗透到循环体外部.

3.3.3 const 声明

声明时必须初始化,常量. 作用域也是块.

3.3.4 声明风格及最佳实践

不使用 var.

const 优先,let 次之.

3.4 数据类型

七种类型:

  • Undefined
  • Null
  • Boolean
  • Number
  • String
  • Symbol
  • Object

3.4.1 typeof 操作符

返回类型,首字母小写. 参数是一个变量.

3.4.2 Undefined 类型

该类型只有 undefined 这一个特殊值.

一般来说,永远不用显式地给某个变量设置 undefined 值.

对未声明和未初始化的变量使用 typeof 返回值都是 undefined. 因此,建议在声明变量时进行初始化,来区分未初始化和未声明.

undefined 是一个假值.

3.4.3 Null 类型

Null 类型同样只有 null 这一个特殊值,null 值表示一个空对象指针.

在定义将来要保存对象值的变量时,建议使用 null 来初始化.

undefined 值是由 null 值派生而来的, 因此 ECMA-262 将它们定义为表面相等.

null 也是一个假值.

3.4.4 Boolean 类型

有两个字面值:

  • true, 和数值 1 不相等
  • false, 和数值 0 不相等

区分大小写,

转换函数 Boolean():

1
2
let message = "Hello World";
let messageAsBoolean = Boolean(message);

几个转换函数:

3.4.5 Number 类型

Number 类型使用 IEEE 754 格式表示整数和浮点值.

十进制数直接写.

八进制第一个数字为 0.

十六进制前缀为 0x.

使用八进制和十六进制格式创建的数值在所有数学操作中都被视为十进制数值.

1. 浮点值

因为存储浮点值使用的内存空间是存储整数值的两倍,所以 ECMAScript 总是倾向于把值转换为整数.

也就是说有些浮点值会被自动转换为整数.

浮点值可以用科学记数法表示:

1
let floatNum = 3.125e7;

e 可以为大写 E.

浮点值的精确度最高可达 17 位小数. 但不要用来比较. 0.1 加 0.2 不等于 0.3, 而是 0.300000000000000004.

2. 值的范围

ECMAScript 可以表示的最小值保存在 Number.MIN_VALUE 中.

ECMAScript 可以表示的最大值保存在 Number.MAX_VALUE 中.

无法表示的负数将被表示为 -Infinity.

无法表示的正数将被表示为 Infinity.

判断是否有限大 isFinite().

3. NaN

NaN, Not a Number, 用于表示本来要返回数值操作失败了.

NaN 不等于 NaN.

1
console.log(NaN == NaN); // false

可以用 isNaN() 判断.

4. 数值转换

将非数值转换为数值的 3 个函数:

  • Number()
  • parseInt
  • parseFloat

后两个用来处理字符串.

3.4.5 String 类型

可用双引号 ", 单引号 ', 反引号标示.

字符串的长度可以通过其 length 属性获取. (如果字符串中包含双字节字符,那么 length 属性返回的可能不准确.)

2. 字符串特点

不可改变 (即,一旦被创建后,其值就不能改变).

修改某个变量中的字符串值,必须先销毁原始的字符串. (销毁过程在后台自动运行)

3. 转换为字符串

几乎所有值都有 toString() 方法.

1
2
3
4
let age = 11;
let ageAsString = age.toString();
let found = true;
let foundString = found.toString();

nullundefined 没有 toString() 方法.

toString() 可接收一个参数表示底数 (输出那个进制):

1
2
3
4
5
let num = 10;
console.log(num.toString()); // "10"
console.log(num.toString(2)); // "1010"
console.log(num.toString(8)); // "12"
console.log(num.toString(10)); // "a"

另一个方法是用 String().

4. 模板字面量

具体见书

5. 字符串插值

也就是在字符串中插入变量, 使用 ${}, 如:

1
2
3
let value = 5;
let exponent = 'second';
let interpolatedString = "value is ${value}";

插入的值会被 toString() 强制转换为字符串 。

6. 模板字面量标签函数 tag function

见书

7. 原始字符串

见书

3.4.7 Symbol 类型

符号用来创建唯一记号.

1. 符号的基本用法

值为符号的变量需要用 Symbol() 函数初始化:

1
2
let sym = Symbol();
console.log(typeof sym);

可以给 Symbol() 传入一个参数作为符号的描述,但是这个值和符号本身的值无关.

Symbol() 函数不能和 new 关键字一起作为构造函数使用.

2. 使用全局符号注册表

见书.

3. 使用符号作为属性

凡是可以使用字符串或数值作为属性的地方,都可以使用符号.

如用作散列的键.

4. 常用内置符号

见书.

3.4.8 Object 类型

ECMAScript 中的对象其实就是一组数据和功能的集合.

对象通过 new 操作符后跟对象类型的名称来创建, 开发者可以通过创建 Object 类型的实例来创建自己的对象,然后再给对象添加属性和方法:

1
let o = new Object();

可以省略括号但不推荐.

Object 对象所含的属性和方法,见书.

valueOf() 返回对象对应的字符串,数值或布尔值表示.

3.5 操作符

+, -, *, /, %, 以及递增,递减都和 C 相同.

3.5.2 位操作符

ECMAScript 中的所有数值都是以 IEEE 754 64 位格式存储,但位操作并不直接应用到 64 位表示, 而是先把值转换为 32 位整数,再进行位操作,之后再把结果转换为 64 位. 因此只需要考虑 32 位整数.

负值以一种称为 二补数 (或补码) 的二进制编码存储.

符号:

  • ~, 非
  • &, 与
  • |, 或
  • ^, 异或
  • <<, 左移
  • >>, 右移
  • >>>, 无符号右移

3.5.5 指数操作符

**

3.5.8 相等操作符

2. 全等和不全等

===!==, 推荐使用,不存在类型转换问题.

3.6 语句

if, do-while, while, for, for-in, for-of.

3.6.7 标签语句

3.6.8 break 和 continue

3.6.9 with 语句

将代码作用域设置为特定对象,如:

1
2
3
let qs = location.search.substring(1);
let hostname = location.hostname;
let url = location.href;

等价于:

1
2
3
4
5
with(location) {
let qs = search.substring(1);
let hostname = hostname;
let url = href;
}

不推荐使用,原因见书.

3.6.10 switch

3.7 函数

语法:

1
2
3
function functionName(arg0, arg1...) {
statements
}

第4章 变量,作用域与内存

4.1 原始值与引用值

JavaScript 不允许直接访问内存位置,因此也就不能直接操作对象所在的内存空间。在操作对象时,实际上操作的是对该对象的引用 (reference) 而非实际的对象本身.

原始值 (primitive value) 是最简单的数据. (Undefined, Null, Boolean, Number, String 和 Symbol)

引用值 (reference value) 是对对象的引用.

4.1.1 动态属性

引用值可以随时添加属性和方法. 而原始值不能.

4.1.2 复制值

引用值复制的值其实是一个指针, 它指向存储在堆内存中的对象.

4.1.3 传递参数

按值传递.

4.1.4 确定类型

使用 instanceof 操作符,判断一个对象是不是某个对象类型:

1
result = variable instanceof constructor

如:

1
console.log(person instanceof Object); // 变量 person 是 Object 吗?

4.2 执行上下文与作用域

每个上下文都有一个关联的 变量对象 (variable object), 而这个上下文中定义的所有变量和函数都存在于这个对象上。虽然无法是通过代码访问变量对象,但后台处理数据会用到它.

4.3 垃圾回收

垃圾回收就是执行环境负责在代码执行时管理内存.

基本思路就是: 确定哪个变量不会再使用,然后释放它占用的内存. 这个过程是周期性的,即垃圾回收程序每隔一定时间就会自动运行.

垃圾回收程序必须追踪纪录哪个变量还会使用,两种主要的标记方法.

4.3.1 标记清理 (mark-and-sweep)

4.3.2 引用计数 (reference couning)

引用数为 0 时回收.

4.3.3 性能

4.3.4 内存管理

将变量设置为 null 来释放引用.

第5章 基本引用类型

引用类型虽然有点像类,但跟类并不是一个概念.

5.1 Date

创建日期对象:

1
let now = new Date();

5.2 RegExp

ECMAScript 通过 RegExp 类型支持正则表达式. 正则表达式使用类似 Perl 的简洁语法来创建:

1
let expression = /pattern/flags;

也可以通过 RegExp 构造函数栏创建:

1
let pattern = new RegExp("[bc]at", "i");

这种方法,元字符需要二次转义.

5.3 原始值包装类型

5.4 单例内置对象

Global 和 Math.


JavaScript-高级程序设计-Notes
http://example.com/2022/11/22/JavaScript-高级程序设计-Notes/
作者
Jie
发布于
2022年11月22日
许可协议