
开始
各个厂商对 JavaScript 都有自己的实现,都遵循 ES 标准
JavaScript 的实现包含三个部分
- ES 标准
- DOM:文档对象模型
- BOM:浏览器对象模型
编写位置
- HTML 文档的 script 标签
- 标签属性
- 通过 scrtip 标签的 src 属性引入.js 文件,引入后标签内的代码无效
注释
1 | // 单行注释 |
使用严格模式:"use strict";
属性访问空安全:obj?.name
globalThis
:对全局对象的抽象,始终指向全局对象
变量
变量声明
1 | var variable; |
常量声明
1 | const variable; |
获取变量类型:typeof variable
数据类型
-
String:双引号,单引号都可以
-
Number
Number.MAX_VALUE 获取 JS 表示的最大值,超过最大值表示为字面量 Infinity,类型 Number
不可计算的结果表示为字面量 NaN,类型 Number
十六进制以 0x 开头,八进制以 0 开头,二进制表示 0b 开头
大整数:数字后跟字符 n,通过
BigInt()
转换 -
Boolean
-
Null
null 值用于表示为空的 Object,null 值的类型是 Object
-
Undefined
undefined 值表示未定义的值,类型为 undefined
-
Object:Object 属于引用类型,其他都属于基本类型
类型强转
-
String()
-
Number():非法数字转换为 NaN
字符串解析为数字
- parseInt(),可以指定进制
- parseFloat()
-
Boolean()
- 0 和 NaN 为 false,其余都为 true
- 空字符串为 false,其余都为 true
- null 和 undefined 为 false
- Object 都为 true
Symbol
Symbol 数据类型表示一个唯一不重复的值,不能进行运算
Symbol 创建
1 | let s = Symbol(); |
var 与 let、const 的区别
-
变量的作用域不同
- var 声明的变量只有全局作用域和函数作用域
- let 声明的变量具有块作用域,全局作用域和函数作用域
- const 声明的变量和 let 作用域相同
-
const
const 声明的是常量,必须在声明时进行初始化,此后变量的值不变
当 const 声明的是对象时,对象为引用类型,变量获取的实际是对象的常量指针,因此变量只能指向该对象,该对象的属性可变
解构赋值
-
数组解构赋值
1
2const arr = [1, 2, 3, 4];
let [i1, i2, i3, i4] = arr; -
对象解构赋值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15const obj = {
name: 'Hello',
age: 20
};
let {name, age} = obj;
// 函数参数解构
function method({name, age}) {
// ...
}
let obj = {
name: "Hello",
age: 20
}
method(obj);
函数
函数声明
1 | function func(parms) { |
函数可作为函数对象使用,适用于闭包
1 | // 构造器生成函数对象 |
函数对象方法:通过函数对象调用,都可以修改函数对象的 this 指向
- call(obj, parms…):传入对象 obj,执行该函数同时将该函数的 this 指向 obj,parms 为函数参数
- apply(obj, parmsArray):将函数的 this 指向传入的 obj,函数参数以数组形式传入
- bind(thisArg):复制一个函数,并设置新函数的 this,设置后不可更改,若第二个参数之后传入参数,则将原函数对应位置参数设为固定值
this、arguments
JavaScript 的 this 以函数为导向,每个函数调用时包含两个隐含参数 this 和 arguments,与原型对象不同,原型对象 prototype 在函数创建时生成,this 和 arguments 在函数调用时传入
this 的值为函数调用的上下文对象 (object context),可理解为指向调用函数的对象
-
对象调用时,this 指向该对象
-
全局函数调用时,this 指向 window 对象
-
函数中调用函数时,this 指向 window 对象
在全局作用域中声明的变量和函数,本质是声明 Window 对象的动态属性
对于变量,使用 var 声明会声明到 Window 对象中,使用 let 声明不会声明到 Window 对象中
arguments 是封装函数参数的对象,是一个伪数组,可以通过下标访问
rest 参数
rest 参数用于代替 arguments,在参数列表中将多余参数包装成伪数组在函数中使用,rest 参数必须在参数列表末尾
1 | function method(...args) { |
扩展运算符 ...
:将数组转换为一个参数序列(在 ES8 中支持对象的扩展运算符)
1 | let arr = [1, 2, 3, 4]; |
扩展运算符的应用
-
数组合并
1
2
3let a = [1, 2];
let b = [3, 4];
let c = [...a, ...b]; // c = [1, 2, 3, 4] -
数组复制:浅拷贝
1
2let a = [1, 2, 3, 4];
let b = [...a]; -
将伪数组转换为真数组
1
2const divs = document.querySelectorAll("div");
const divArr = [...divs];
箭头函数
类似于 lambda 表达式
1 | let hello = function (a, b) { |
箭头函数 this 的指向:function 函数有自己的 this 值,指向调用该函数的对象 (object context),箭头函数没有自己的 this 值,其 this 值通过继承函数作用域链上最近的函数获取
箭头函数不能使用 call、apply、bind 函数改变 this 指向
1 | let circle = { |
数组
JavaScript 数组可以动态扩容,且可以同时存放任意类型,length 属性返回数组长度
1 | // new创建 |
数组遍历
- for 三段式
- for-in:获取可迭代对象的键,可遍历数组和对象属性,最好用于遍历对象属性
- for-of:获取可迭代对象的值,可遍历数组和对象属性,最好用于遍历数组
数组方法
- push():在尾部添加任意个数元素,返回新的长度
- pop():删除最后一个元素,返回该元素
- unshift():在开头添加任意个数元素,返回新的长度
- shift():删除第一个元素,返回该元素
- forEach():传入一个函数对象,对数组元素执行该函数,函数对象中的参数分别为数组元素,下标,整个数组
- slice(start, end):[start, end),数组切片并返回,支持负数倒数索引
- splice(start, n, obj…):删除指定索引开头的 n 个元素并已数组形式返回,在 start 处插入多个 obj
- concat():连接多个数组并返回新数组
- join():将数组以字符串返回,可以传入字符串指定分隔符
- reverse():反转数组
- sort():排序,默认按照字典序排序,传入一个函数对象指定 Comparator
对象
对象的分类
- ES 标准对象:String、Object 等
- 浏览器对象:console、document 等
- 自定义对象
对象创建
判断对象中是否存在某个属性:attr in obj
,attr 类型为 String,以属性名匹配变量
1 | let person = { |
声明一个 Object 类型对象
1 | let obj = new Object(); |
可以在声明对象后,在外部动态赋值属性
1 | let obj = {}; // Object类型 |
使用计算属性(动态属性名)
1 | let a = "Hello"; |
可以声明其他类型的对象,动态赋值属性
1 | let obj = new String(); |
对象使用
属性访问和下标访问
1 | obj.n // 属性访问将输入的属性名作为变量与对象属性变量进行匹配,若没有该属性则返回undefined |
for/in 遍历对象字段
1 | for (let n in obj) { |
对象方法
1 | let obj = { |
对象简化写法
对象字面量声明对象时,传入变量时简化属性名
1 | let name = "Hello"; |
类
模拟类
早期 JavaScript 不支持类,可以通过一些方法模拟类
构造函数
经典方法
1 | function Person(name, age) { |
模拟类方法 (极简方法)
使用对象模拟一个类,其中定义构造函数
Javascript定义类(class)的三种方法 - 阮一峰的网络日志 (ruanyifeng.com)
1 | var Person = { // 建议const |
使用该方法创建的对象总是 Object 类型 ({}类型)
1 | let p = Person.create(name); |
该方法使用简单,便于理解,在不需要类型判断时可以使用
继承
使用极简方法可以很容易地实现继承的效果
1 | const Animal = { |
访问限制
使用极简方法来模拟私有字段/方法和公有字段/方法
1 | const Cat = { |
类字段和类方法
使用极简方法来模拟类字段和类方法
1 | const Cat = { |
将类字段/方法与对象关联,使得对象可以操作类字段/方法
1 | const Cat = { |
class 类
在 ES6 中,js 添加了类功能,可以使用 class 声明一个类
1 | class Person { |
封装
私有属性使用 #
前缀
1 | class Person { |
继承与多态
js 使用 extends 实现继承,支持方法重写
1 | class Animal { |
多态:js 是动态语言,它的多态并不依赖于继承,在使用一个未知类型对象时,只关心该对象内部是否有相应的属性或方法
原型对象
每个函数、对象都自动存在一个原型对象,隐含的 prototype 属性指向原型对象,而原型对象中的 constructor 属性指向该函数对象

当函数以构造函数的形式调用时 (类实例化),该构造函数创建的对象中会包含一个隐含属性__proto__,该属性指向原型对象
若函数是构造函数,则类中声明的方法会存储在原型对象中
1 | fun.prototype // 函数访问自己的原型对象,通常使用该方式访问原型对象 |
原型对象可看做一个类对象 (静态),其中定义的属性和方法可作为各个对象实例的类字段和类方法
创建出对象或构造函数后,可以向原型对象里动态定义字段和方法
1 | function Person(name) { |
instanceof
instanceof 用于判断对象实例类型,判断实例是否是某个构造函数创建的,不能用于判断原型对象
TypeException:Right-hand side of 'instanceof' is not callable
,instanceof 的右值必须是可调用的
instanceof 实际是判断实例对象的__proto__ 和构造函数的 prototype 是否相同
1 | function Person(name) { |
原型链
构造函数与对象的原型关系

两种构造方法的原型链
经典方法 (对应类实例化):真正的创建了 Person 构造函数,生成了 Person 的原型对象

极简方法或字面量方法:本质上 person 是个 Object 对象,没有创建新的原型对象

原型继承:js 继承通过原型链实现,子类的原型对象就是父类的实例对象
对象方法
-
hasOwnProperty
:判断对象实例自身的字段使用
obj.hasOwnProperty("attr")
判断对象实例自身的字段,不包含原型对象的字段1
2
3
4
5
6
7function Person(name) {
this.name = name;
}
let p = new Person(name);
Person.prototype.age = 20;
"age" in p // true
p.hasOwnProperty("age") // false -
Object.is
:判断两个对象是否完全相等 -
Object.assign
:对象合并,将后一参数对象合并到前一参数对象,若出现重名成员,则覆盖 -
Object.setPrototypeOf
:设置对象原型对象 -
Object.getPrototypeOf
:获取对象原型对象 -
Object.fromEntries
:通过二维数组或 Map 来创建对象 -
Object.entries
:将对象转换为二维数组
常用工具对象
Date
创建 Date 对象自动以当前时间创建
1 | const date = new Date(); |
方法
- getDate():返回日期
- getDay():返回日期是周几,周日返回 0
- getMonth():返回月份,从 0 开始
- getFullYear():返回年份
- getTime():返回时间戳 (自 1970 年 1 月 1 日到至今的毫秒数)
- Date.now():获取当前时间戳
字符串
字符串支持下表访问,length 获取字符串长度
- charCodeAt():返回指定位置字符的 Unicode 编码
- String.fromCharCode():返回 Unicode 编码对应的字符
- concat():连接多个字符串
- indexOf(char, start):获取字符串中字符的索引,不存在则返回 -1,start 指定开始查找的位置
- lastIndexOf():从尾部查找字符的索引
- slice():获取子串
- substring():获取子串,不支持负数索引
- split():字符串分割为数组,传入字符串分隔符,传入空串,则以每个字符分割
- search():搜索字符串中的子串,返回第一次出现的索引,不存在则返回 -1
- replace():将字符串中的第一个指定子串替换为新内容
- trimStart():去除字符串起始空白
- trimEnd():去除字符串末尾空白
- trim():去除字符串起始和末尾空白
正则表达式
JavaScript 正则表达式使用 RegExp 对象封装
1 | let reg = new RegExp("expression", "pattern"); |
pattern
- “i”: 忽略大小写
- “g”: 全局匹配
相关方法
- test(str):测试 str 是否符合正则表达式
- 与字符串相关,由字符串调用
- split():传入正则表达式,根据正则表达式的匹配结果分割字符串,默认全局匹配
- search():传入正则表达式,返回第一个匹配结果的索引,不支持全局匹配
- match():传入正则表达式,返回第一个匹配结果,正则设置为全局匹配 g,返回所有匹配结果的数组
- replace():传入正则表达式,将第一个匹配结果替换为新内容,正则设置为全局匹配 g,将所有匹配结果替换
JSON
JSON.parse(jsonString)
:将 json 字符串转换为 json 对象JSON.stringify(obj)
:将 js 对象转换为 json 字符串
Map
Map 的键值支持任意对象
1 | let map = new Map() |
Set
1 | let set = new Set() |
迭代器
迭代器用于 for…of 访问,实际通过 Symbol.iterator
方法获取迭代器 Iterator,调用 Iterator 的 next 方法遍历,next 方法返回一个包含 value
和 done
两个属性的对象,value 为遍历值,done 表示遍历是否完成
自定义迭代器
1 | class MyArray { |
生成器
生成器是一个函数,可以实现代码逻辑的迭代执行
1 | function* generate() { |
生成器传参
1 | function* generate(arg) { |
模块化
在 ES6 之前有许多模块化规范
- CommonJS:NodeJS
- AMD:requireJS
- CMD:SeaJS
模块化语法
导出:export
1 | // 导出变量 |
导出:import
1 | // 导入所有成员 |