《JavaScript高级程序设计》读书笔记
语法
- 区分大小写
- 标识符:变量、函数、属性或函数参数的名称。第一个字符必须是字母、下划线(_)或美元符号,剩下可以是字母、下划线、美元符号、数字。(字母可以是扩展ASCII中的字母)
- 注释:// 单行注释。/* 多行注释 */ 。
- 严格模式:“use strict”。可以在脚本开头或者函数体开头。
关键字与保留字
break | do | in | typeof | case | else | instanceof | var | catch |
new | void | class | extends | return | while | const | finally | super |
continue | for | switch | yield | debugger | function | this | default | if |
delete | import | try | enum | implements | package | public | interface | protected |
let | private | await | export | with | throw | static |
变量
var:函数作用域,声明的变量会自动提升到函数作用域顶部,多余的合并为一个声明。在函数内定义变量省略var,创建为全局变量。在全局变量中声明会成为window对象属性。
let:块作用域,不存在变量提升,在声明前调用会报错,称为暂时性死区。
const:与let相同,区别是它声明变量时必须同时初始化变量,且尝试修改会导致运行错误。
数据类型
6中简单数据类型(原始类型):
- Undefined
- Null
- Boolean
- Number
- String
- Symbol
复杂数据类型:Object
typeof操作符
对一个值使用typeof操作符会返回下列字符串之一:
- "undefined" 未定义
- "boolean" 布尔值
- "string" 字符串
- "number" 数值
- "object" 对象或null
- "function" 函数
- "symbol" 符号
Undefined 类型
当使用var 或 let 声明了变量但没有初始化时,就相当于给变量赋予了该值。
Null 类型
空对象指针,所有使用 typeof 会返回 "object" 。
null == undefined; // true
Boolean 类型
true 和 false。
转换规则:
数据类型 | 转化为true的值 | 转化为false的值 |
Boolean | true | false |
String | 非空字符串 | ""(空字符串) |
Number | 非零数值(包括无穷值) | 0、NaN |
Object | 任何对象 | null |
Undefined | N/A(不存在) | undefined |
Number 类型
使用了IEEE 754格式表示整数和浮点数(也叫双精度值)。
八进制第一个数字必须是零,严格模式下前缀0会被视为语法错误,应该使用0o。十六进制0x开头(0~9以及A~F,大小写均可)。
浮点值:数值中必须包含小数点,而且小数点后面必须至少一个数字。对于非常大或小可用科学记数法(3.1e3 == 3100)
值的范围:Number.MIN_VALUE ~ Number.MAX_VALUE。超出转换为Infinity 、-Infinity。isFinite() 函数去检测。
NaN:不是数值,用于表示本来要返回数值的操作失败了。NaN不等于NaN,可以通过isNaN() 去判断。
数值转换:
- Number()
- 布尔值,true 为 1,false 为 0
- 数值直接返回
- null 返回 0
- undefined 返回 NaN
- 字符串包含数值返回十进制数值。空字符返回0。不符合条件返回NaN。
- 对象,调用 valueOf() 方法,如果为 NaN,则再调用 toString() 方法,再按照字符串的规则转换
- parseInt()
- parseFloat()
String 类型
表示零或多个16位 Unicode 字符序列。可以是 "、'、`。
字符字面量:
- \n 换行
- \t 制表
- \b 退格
- \r 回车
- \f 换页
- \\ 反斜杠
- \' 单引号
- \" 双引号
- \` 反引号
- \xnn 以十六进制编码 nn 表示的字符
- \unnn 以十六进制编码nnnn表示的Unicode字符
字符串特点:一旦创建,值不能改变。要修改某个变量中的字符串值,必须先销毁原始的字符串,然后将包含新值得另一个字符串保存到该变量。
转换为字符串:toString()
模板字面量:` `
模板字面量标签函数:自定义插值。`${ a }`
原始字符串:String.raw`\u00A9`,不转换。
Symbol 类型
符号是原始值,且符号实例是唯一、不可变的。确保对象属性使用唯一标识符,不会发生属性冲突的危险。
基本使用 :
let sym = Symbol();
console.log(typeof sym); // symbol
let sym2 = Symbol('foo'); // 可传入一个描述,无标识效果
// 不允许使用new,如果确实想使用符号包装对象,可以借用Object()函数
let mySymbolObj = Object(Symbol());
使用全局符号注册表 Symbol.for :
运行时不同部分需要共享和重用符号实例。Symbol.for() 对每个字符串执行幂等操作,第一次使用某个字符串调用时,检查全局运行时注册表,不存在则生成一个新符号并添加到注册表中,如果有则返回该符号实例。(可用Symbol.keyFor() 查询该符号对应的字符串键)
let a = Symbol.for('foo');
let b = Symbol.for('foo');
console.log(a == b); // true
console.log(Symbol.keyFor(a)); // foo
使用符号作为属性
定义属性:Object.defineProperty() / Object.defineProperties。
Object.getOwnPropertyNames() 返回对象实例的常规属性数组,Object.getOwnPropertySymbols() 返回对象实例的符号属性数组。这两个互斥
Object.getOwnPropertyDescriptors() 返回同时包含常规和符号属性描述符的对象。
Reflect.ownKeys() 返回两种类型的键。
Symbol.asyncIterator
该方法返回对象默认的AsyncIterator。由for-await-of 语句使用。实现异步迭代器API的函数。
class Foo {
async *[Symbol.asyncIterator]() {}
}
let f= new Foo();
console.log(f[Symbol.asyncIterator]()); // AsyncGenerator {<suspended>}
// 该函数生成的对象应该通过其next()方法陆续返回Promise实例。可以显示地调用next()方法返回,也可以隐式地通过异步生成器函数返回
class Emitter {
constructor(max) {
this.max = max;
this.asyncIndex = 0;
}
async *[Symbol.asyncIterator]() {
while(this.asyncIndex < this.max) {
yield new Promise((res) => res(this.asyncIndex++));
}
}
}
async function asyncCount() {
let e = new Emitter(5);
for await(const x of e) {
console.log(x);
}
}
asyncCount()
// 0
// 1
// 2
// 3
// 4
Symbol.hasInstance
一个方法,该方法决定一个构造器对象是否认可一个对象是它的实例。由 instanceof 操作符使用。
Symbol.isConcatSpreadable
一个布尔值,如果是true,对象应该用Array.prototype.concat()打平其数组元素。false或假值则整个对象被追加到数组末尾。
Symbol.iterator
一个方法,该方法返回对象默认的迭代器。有for-of语句使用。
class Emitter {
constructor(max) {
this.max = max;
this.idx = 0;
}
* [Symbol.iterator]() {
while(this.idx < this.max) {
yield this.idx++
}
}
}
let emitter = new Emitter(5)
for(const x of emitter) console.log(x)
// 0
// 1
// 2
// 3
// 4
Symbol.match
一个正则表达式方法,该方法用正则表达式去匹配字符串。由 String.prototype.match() 方法使用。(正则表达式原型上默认由这个函数定义)
console.log(RegExp.prototype[Symbol.match])
// ƒ [Symbol.match]() { [native code] }
console.log('foobar'.match(/bar/));
// ['bar', index: 3, input: 'foobar', groups: undefined]
class FooMatch {
static [Symbol.match](target) {
return target.includes('foo');
}
}
'foobar'.match(FooMatch)
//true
Symbol.replace
一个正则表达式方法,该方法替换一个字符串中匹配的字串。String.prototype.replace() 方法会使用以 Symbol.replace 为键的函数来对正则表达式求值。
Symbol.search
一个正则表达式方法,该方法返回字符串中匹配正则表达式的索引。由Sting.prototype.search() 方法使用。
Symbol.species
一个函数值,该函数作为创建派生对象的构造函数。
Symbol.split
一个正则表达式方法,该方法在匹配正则表达式的索引位置拆分字符串。由String.prototype.split() 方法使用。
Symbol.toPrimitive
一个方法,该方法将对象转换为相应的原始值。由 Toprimitive 抽象操作使用。很多内置操作都会尝试强制将对象转化为原始值,包括字符串、数值和未指定的原始类型。
Symbol.toStringTag
一个字符串,该字符用于创建对象的默认字符串描述。由内置方法 Object.prototype.toString() 方法使用。
Symbol.unscopables
一个对象,该对象所有的以及继承属性,都会从关联对象的with环境绑定中排除。设置这个符号并让其映射对应属性的键值为true,就可以阻止该属性出现在with环境绑定中。
Object 类型
属性和方法:
- constructor:用于创建当前对象的函数
- hasOwnProperty:用于判断当前对象实例上是否存在给定的属性
- isPrototypeof:用于判断当前对象是否为另一个对象的原型
- propertyIsEnumerable:用于判断给定的属性是否可以使用
- toLocaleString():放回对象的字符串表示,该字符串反射对象所在的本地化执行环境
- toString():返回对象的字符串表示
- valueOf():返回对象对应的字符串、数组或布尔值表示。
操作符
一元操作符
- 递增/递减操作符
- 前缀版:++age,--age
- 后缀版:age++,age--
- 一元加和减(多用于数据类型转换)
- +
- -
位操作符
ECMAScript 中所有数值都以 IEEE 756 64位格式存储,但位操作并不直接应用到64位表示,而是先把值转换为32位整数,在进行位操作,之后再把结果转化为64位。
有符号整数使用32位的前31位表示整数值。第32位表示数值的符号,如0表示正,1表示负,称为符号位。
- 正值以真正的二进制格式存储,即31位中的每一位都代表2的幂。
- 负值以一种称为二补数的二进制编码存储,步骤如下:
- 确定绝对值的二进制表示
- 找到数值的一补数,即每个0变成1,每个1变成0
- 给结果加1
按位非(~)
返回数值的一补数。对数值取反并减1。
按位与(&)
将两个数的每一个为对齐
第一个数值的位 | 第二个数值的位 | 结果 |
1 | 1 | 1 |
1 | 0 | 0 |
0 | 1 | 0 |
0 | 0 | 0 |
let result = 25 & 3; // 1
计算过程:
25 = 0000 0000 0000 0000 0000 0000 0001 1001
3 = 0000 0000 0000 0000 0000 0000 0000 0011
---------------------------------------------------------------------
0000 0000 0000 0000 0000 0000 0000 0001
按位或(|)
第一个数值的位 | 第二个数值的位 | 结果 |
1 | 1 | 1 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
按位异或(^)
第一个数值的位 | 第二个数值的位 | 结果 |
1 | 1 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
左移(<<)
按照指定的位数将数值的所有位向左移动。(符号位保留)
有符号右移(>>)
向右移,保留符号。
无符号右移(>>>)
对于正数,与有符号右移结果相同。对于负数,将负数的二进制表示当成正数的二进制表示来处理
相关操作符
- 布尔操作符
- 逻辑非 !
- 逻辑与(短路操作符) &&
- 逻辑或 ||
- 乘性操作符 *
- 除法操作符 /
- 取模操作符 %
- 指数操作符 ** (Math.pow)
- 加法操作符 +
- 减法操作符 -
- 关系操作符
- >
- <
- <=
- >=
- 相等操作符
- ==
- !=
- ===
- !===
- 条件操作符
- ? :
- 赋值操作符 =
- 逗号操作符 ,
语句
if 语句:if(condition) statement1 else statement2
do - while 语句:后测试循环语句,至少执行一次
while 语句:先测试循环语句
for 语句:先测试语句。初始化、条件表和循环后表达式都不是必需的
for - in 语句:严格的迭代语句,用于枚举对象中的非符号键属性
for - of 语句:严格的迭代语句,用于遍历可迭代对象的元素
标签语句:用于给语句加标签。label: statement
break 和 continue 语句:对迭代循环的控制手段
with 语句:将代码作用域设置为特定的对象。with(expression) statement
switch 语句:流控制语句
函数
使用 function 关键字声明,后跟一组参数,然后是函数体。
严格模式对函数的限制:
- 函数不能以eval 或 arguments 作为名称
- 函数的参数不能叫 eval 或 arguments
- 两个函数的参数不能叫同一个名称