原型与原型链
原型prototype
- 函数的prototype属性(图)
- 每个函数都有一个prototype属性,它默认指向一个Object空对象(即称为原型对象)
- 原型对象中有一个属性constructor,他指向函数对象
- 给原型对象添加属性(一般都是方法)
- 作用:函数的所有实例对象自动拥有原型中的属性(方法)
显式原型与隐式原型
- 每个函数function都有一个prototype,即显式原型(属性)
- 每个实例对象都有一个__proto__,可称为隐式原型(属性)
- 对象的隐式原型的值是其对应构造函数的显式原型的值
- 内存结构
- 总结:
- 函数的prototype属性:在定义函数时自动添加的,默认值是一个空Object对象
- 对象的__proto__属性:创建对象时自动添加的,默认值为构造函数的prototype属性值
- 程序员能直接操作显式原型,但不能直接操作隐形原型(ES6之前)
原型链
- 原型链
- 访问一个对象时:
先在自己的属性中查找,找到返回
如果没有,在沿着__proto__这条链向上查找,找到返回
如果最终没有找到,返回undefined
- 别名:隐式原型链
- 作用:查找对象的属性(方法)
注意:
- 函数的显式原型指向的对象默认是空Object实例对象(但Object不满足)
- 所有函数都是Function的实例(包括Function)
Function.__proto__===Function.prototype - Object的原型对象是原型链尽头
- 读取对象的属性值时:会自动到原型链中查找
- 设置对象的属性值时:不会查找原型链,如果当前对象中没有此属性,直接添加此属性并设置其值
- 方法一般定义在原型中,属性一般通过构造函数定义在对象本身上
执行上下文与执行上下文栈
执行上下文
- 代码分类(位置)
- 全局代码
- 函数(局部)代码
- 全局执行上下文
- 在执行全局代码前将window确定为全局执行上下文
- 对全局数据进行预处理
var定义的全局变量==>undefined,添加为window的属性
function声明的全局函数==>赋值(fun),添加为window的方法
this==>赋值(window)
- 开始执行全局代码
- 函数执行上下文
- 在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象(虚拟的,存在于栈中)
- 对局部数据进行预处理
形参变量==>赋值(实参)==>添加为执行上下文属性
argument==>赋值(实参列表),添加为执行上下文的属性
var定义的局部变量==>undefined,添加为执行上下文的属性
function声明的函数==>赋值(fun),添加为执行上下文的方法
this==>赋值(调用函数的对象)
- 开始执行函数体代码
执行上下文栈
-
- 在全局代码执行前,JS 引擎就会创建一个栈来存储管理所有的执行上下文对象
-
- 在全局执行上下文(window)确定后,将其添加到栈中(压栈)
-
- 在函数执行上下文创建后,将其添加到栈中(压栈)
-
- 在当前函数执行完后,将栈项的对象移除(出栈)
-
- 当所有的代码执行完后,栈中只剩下window
Event Loop 的执行顺序
宏任务
- Task Queue
- 常见宏任务:setTimeout、setInterval、setImmediate、I/O、script、UI rendering
微任务
- Job Queue
- 常见微任务:
- 浏览器:Promise、MutationObserver
- Node.js:process.nextTick
执行顺序
- 首先执行同步代码,宏任务
- 同步栈为空,查询是否有异步代码需要执行
- 执行所有微任务
- 执行完,是否需要渲染页面
- 重新开始 Event Loop,执行宏任务中的异步代码