function Fn() {
// ...
}
let f1 = Fn();
let f2 = new Fn();
普通函数执行,是把 Fn 函数执行的结果返回给 f1。构造函数执行,把 Fn 当做一个类,是把创造的一个实例返回,f2 是创造出来的一个实例。
全局执行上下文进栈执行
- 初始化变量对象(VO)
- 初始化作用域链<
> - 初始化 this
- 初始化 arguments(没有)
- 形参赋值(没有)
- 变量提升,Fn 变量提升,声明 + 定义(let 没有变量提升,所以 f1、f2 不会声明也不会在这个阶段被定义)
-
全局上下文代码执行
Fn 不做任何操作,在上一步已经被声明+ 定义
- f1 = Fn(),普通函数执行,函数执行创建一个新的执行上下文进栈执行
f2 = new Fn(),构造函数执行,大多数构造函数执行和普通函数执行是一样的,但是有几点不太一样。
Fn(f1) 进栈执行
Fn(f1) 私有上下文进栈执行
- 初始化变量对象 AO(f1)
- 初始化作用域链<
> - 初始化 this
- 初始化 arguments
- 形参赋值
- 变量提升
- 代码执行 …
- 函数由于没有返回,所以默认返回 undefined,f1 被赋值为 undefined ,在全局的 VO(G) 中 f1 = undefined
- 函数执行完成出栈
Fn(f2) 进栈执行
- Fn(f2) 私有上下午进栈执行
- 初始化变量对象 AO(f2)
- 在构造函数执行,初始化作用域链之前,浏览器会默认先创建一个对象(空对象,Fn 的实例对象)
- 初始化作用域链<
> - 初始化 this,这里的初始化 this,会将 this 指向第三步创建的对象,所以在后期代码中执行 this.xx = xx 的时候,实际上就是在往这个对象(实例对象)上添加属性或者方法,这里还需要注意下,构造函数执行,函数内部的私有变量和实例是没有关系的。
- 初始化 arguments
- 形参赋值
- 变量提升
- 代码执行
- 函数执行完,出栈之前,会查看构造函数本身的返回结果:
- 如果有 「return 对象」,则以返回值为主,f2 就会等于这个返回值对象。
- 如果没有返回值或者返回的是一个原始值,则浏览器默认会将创建的实例返回,f2 就会等于这个实例对象
- 函数出栈