JavaScript 深入解析
一、Promise 相关
1. then 方法的行为
- 两个参数:
.then(onFulfilled, onRejected)
onFulfilled:Promise 状态变为 fulfilled 时执行
onRejected:Promise 状态变为 rejected 时执行
- 重要特性:若
onRejected 函数捕获了 rejection,后续的 .catch() 将无法捕获同一个错误。
2. 参数非函数的处理
- 当任一参数不是函数时,该参数会被忽略
- 若
onFulfilled 不是函数,会导致 resolve 的值透传到后续的 .then()
- 若
onRejected 不是函数,会导致 reject 的原因透传到后续的 .catch()
3. Resolve 与 Reject 的执行时机
resolve() 和 reject() 方法是同步执行的
- 调用后立即改变 Promise 状态,并将对应的回调函数放入微任务队列
- 后续的
.then() 或 .catch() 会在当前同步代码执行完毕后执行
4. catch 方法的本质
- 语法糖:
catch(onRejected) 等同于 then(null, onRejected)
- 错误传递:若
onRejected 函数中抛出新的错误,会被后续的 .catch() 捕获
5. Promise 构造函数
- 接收一个执行器函数作为参数:
new Promise((resolve, reject) => { ... })
- 只有调用
resolve() 或 reject() 才能改变 Promise 状态
- 若不调用,Promise 将永远处于
pending 状态
6. await 的行为
await 表达式会暂停 async 函数的执行
- 等待 Promise 完成后,将后续代码包装为微任务继续执行
- 即使
await 的是一个非 Promise 值,后续代码也会作为微任务执行
7. async 函数的错误处理
- 内部抛出错误或 Promise 被 reject 会暂停函数执行
- 错误会沿着调用链向上查找
catch
- 若被捕获,继续执行
catch 后的代码
- 若未被捕获,会导致 async 函数返回一个 rejected 的 Promise
8. finally 方法
- 无论 Promise 结果是
fulfilled 还是 rejected 都会执行
- 无参数:回调函数不接收任何参数
- 同步执行:是 Promise 链的一部分
- 返回一个新的 Promise,继承原 Promise 的状态(除非在
finally 中抛出错误)
二、JavaScript 作用域
1. 作用域类型
- 全局作用域:在函数和代码块之外声明的变量
- 函数作用域:在函数内部声明的变量(
var 声明的变量属于函数作用域)
- 块级作用域:ES6 引入,由
{ } 界定(let、const 声明的变量)
- 箭头函数:没有自己的作用域,继承最近的外层作用域
2. 词法作用域(静态作用域)
- 变量查找基于代码定义时的位置,而非运行时
- 当前作用域找不到变量时,会向上级作用域逐层查找
- 与函数如何调用无关
3. this 指向规则
- 普通函数:取决于调用时的上下文
- 直接调用:非严格模式下指向
window,严格模式下为 undefined
- 对象方法调用:指向调用该方法的对象
- 构造函数调用:指向新创建的对象
- 箭头函数:继承定义时最近外层作用域的
this,且不可更改
4. 变量访问规则
- 访问未声明的变量:抛出
ReferenceError
- 访问对象不存在的属性:返回
undefined
- 未使用关键字声明变量(非严格模式):自动成为全局变量
5. 作用域链
- 函数声明时,其作用域链就已经确定
- 包含函数自身作用域和所有外层作用域
- 变量查找沿作用域链向上进行
6. 严格模式的影响
- 启用严格模式:
"use strict"
- 阻止自动创建全局变量
- 禁止删除不可删除的属性
- 函数参数名不能重复
this 在全局作用域中为 undefined(而非 window)
三、原型与原型链
1. 原型基本概念
__proto__:对象的隐式原型,指向其构造函数的 prototype
prototype:函数的显式原型,用于构建实例的原型对象
- 关系:
实例.__proto__ === 构造函数.prototype
2. 原型链查找机制
- 访问对象属性时,先查找自身属性
- 若不存在,则通过
__proto__ 向原型链上层查找
- 直到找到属性或到达原型链终点(
Object.prototype.__proto__ 为 null)
3. 原型链终点
- 所有原型链的终点是
Object.prototype
Object.prototype.__proto__ === null
- 示例:
String.prototype.__proto__ === Object.prototype
4. constructor 属性
- 原型对象有一个
constructor 属性,指向其构造函数
- 示例:
实例.constructor === 构造函数
构造函数.prototype.constructor === 构造函数
5. 类型判断方法
instanceof:检查构造函数的 prototype 是否在对象的原型链上
typeof:返回基本类型的字符串表示
- 注意:
typeof null === 'object'(历史遗留问题)
- 函数返回
'function'
Object.prototype.toString.call():获取精确类型信息
6. 基本类型的特殊行为
- 基本类型(
string、number、boolean)本身没有属性
- 访问其属性时,JavaScript 会自动创建临时包装对象
- 包装对象继承对应构造函数的
prototype 上的方法
- 访问完成后包装对象被销毁
7. 原型链示意图
实例对象
↓ __proto__
构造函数.prototype
↓ __proto__
Object.prototype
↓ __proto__
null
8. 修改原型的影响
- 修改构造函数的
prototype 会影响所有已创建和将创建的实例
- 修改实例的
__proto__ 会改变其原型链(不推荐)
- 最佳实践:通过
Object.create() 创建具有指定原型的新对象
总结要点
Promise 核心
- Promise 状态不可逆,then/catch 返回新 Promise
- 微任务优先级高于宏任务
- async/await 是基于 Promise 的语法糖
作用域关键
- 词法作用域决定变量查找
- 闭包是函数和其词法环境的组合
this 的动态绑定是常见困惑点
原型链本质
- JavaScript 基于原型的继承机制
- 所有对象(除
null)都有原型
- 原型链是实现继承和共享属性的基础