步骤
- 首先创建一个空对象
- 将该空对象的原型指向构造函数的原型
- 将构造函数的this指向该空对象,并且执行构造函数(这一步就是为例改变this的指向,也是常说的将空对象作为构造函数的上下文,然后执行构造函数) ---- 对象的初始化操作
- 最后对构造函数的返回值进行判断
如果构造函数返回一个引用类型的数据,则该数据会直接作为new操作的返回值
如果构造函数返回一个基本类型的数据,则会返回新创建并已初始化后的对象
如果构造函数中抛出异常,那么new操作就会失败
手动实现new操作步骤
// 原本new操作
function Person(name) {
this.name = name;
};
console.log(new Person('lbj'))
// 原本new操作
function Person(name) {
this.name = name;
};
console.log(new Person('lbj'))
// 手写一个new操作
function createObj(fn,...args) { // 第一个参数一定是构造函数,后面的参数可以是一个或者多个形参,所以我么用扩展运算符进行接收
// 第一步 创建对象
let obj = {}; // 可以字面量形式
// let obj = Object.create({}); 也可以使用Obkject.create
// 第二步 将新对象的原型指向构造函数的原型
// obj.__proto__ = fn.prototype; // 这种写法也是可以的但是不推荐因为__proto__是隐式属性,也不推荐直接使用__proto__属性
Object.setPrototypeOf(obj,fn.prototype);
// 第三步 将构造函数的this指向新对象并执行构造函数
let result = fn.apply(obj,args); // 这里为啥用apply因为args是数组 如果参数不是数组是已知数量的参数 我们也可以使用call
// 第四部判断构造函数返回的数据 (一般为undefined)
return result instanceof Object ? result : obj; // 是引用数据就直接返回result否则返会新创建的对象
}
console.log(createObj(Person,'lbj'))
两种方式效果是一样的