一、new 做了什么?

(1) 创建一个新对象;
(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象) ;
(3) 执行构造函数中的代码(为这个新对象添加属性) ;
(4) 返回新对象。

二、如何实现

// 方法一
function myNew() {
  // 通过arguments类数组打印出的结果,我们可以看到其中包含了构造函数以及我们调用objectfactory时传入的其他参数
  // 接下来就是要想如何得到其中这个构造函数和其他的参数
  // 由于arguments是类数组,没有直接的方法可以供其使用,我们可以有以下两种方法:
  // 1. Array.from(arguments).shift(); //转换成数组 使用数组的方法shift将第一项弹出
  // 2.[].shift().call(arguments); // 通过call() 让arguments能够借用shift方法
  const Constructor = [].shift.call(arguments);
  const args = arguments;
  // 新建一个空对象 纯洁无邪
  let obj = new Object();
  // 接下来的想法 给obj这个新生对象的原型指向它的构造函数的原型
  // 给构造函数传入属性,注意:构造函数的this属性
  // 参数传进Constructor对obj的属性赋值,this要指向obj对象
  // 在Coustructor内部手动指定函数执行时的this 使用call、apply实现
  Constructor.call(obj, ...args);
  return obj;
}

// 方法二
function createNew() {
  //创建一个空对象
  let obj = new Object();
  //获取构造函数
  let Constructor = [].shift.call(arguments);
  //链接到原型
  obj.__proto__ = Constructor.prototype;
  //绑定this值
  let result = Constructor.apply(obj, arguments); //使用apply,将构造函数中的this指向新对象,这样新对象就可以访问构造函数中的属性和方法
  //返回新对象
  return typeof result === "object" ? result : obj; //如果返回值是一个对象就返回该对象,否则返回构造函数的一个实例对象
}

三、测试实例

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.say = function () {
    console.log("I am " + this.name);
  };
}

//通过 new 创建构造实例
let person1 = new Person("Curry", 18);
console.log(person1.name); //"Curry"
console.log(person1.age); //18
person1.say(); //"I am Curry'

//通过 myNew() 方法创造实例
let person2 = myNew(Person, "Curry", 18);
console.log(person2.name); //"Curry"
console.log(person2.age); //18
person2.say(); //"I am Curry'

//通过 createNew() 方法创造实例
let person3 = createNew(Person, "Curry", 18);
console.log(person3.name); //"Curry"
console.log(person3.age); //18
person3.say(); //"I am Curry'