Javascript中的New操作、Object.create以及Reflect.construct的对比

5/11/2021 Javascript

在 JavaScript 中,new 操作符用于创建一个新的对象,新对象将会继承类的所有属性和方法。主要的目标是将新对象的 __proto__ 属性指向构造函数的原型,从而实现原型链继承。当我们使用 new 操作符时,实际上会执行以下四个步骤:

  1. 创建一个新的 JavaScript 对象,并将 this 指向该对象。
  2. 将新对象的 __proto__ 属性指向构造函数的原型(constructor.prototype),从而实现对原型链上方法和属性的访问。
  3. 将构造函数内部的赋值属性变成新对象的私有属性。
  4. 如果构造函数没有返回引用类型的值,则将这个新的 JavaScript 对象返回。

# 使用 Object.create 实现自定义 new 操作符

下面是一个使用 Object.create 方法手写自定义 new 操作符的示例代码:

function newFactory(ctor, ...args) {
  if (typeof ctor !== 'function') {
    throw new Error('The first parameter of newFactory must be a function');
  }

  const obj = Object.create(ctor.prototype); // 继承构造函数的原型
  const res = ctor.apply(obj, args); // 将私有变量赋值给新对象
  const isObject = typeof res === 'object' && res !== null; // 判断是否是引用类型(排除 null)
  const isFunction = typeof res === 'function'; // 判断是否是函数

  return isObject || isFunction ? res : obj; // 返回引用类型或者函数,否则返回新对象
}

# 使用 [Object.create](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create) 创建新对象

Object.create(proto) 方法是用来创建一个新的对象的,它会将对象的 __proto__ 属性指向传入的构造函数。这是一个常用的对象创建方法,也是实现自定义 new 操作符的一种方式。例如:

const person = {
  isHuman: false,
  printIntroduction: function () {
    console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
  },
};

const me = Object.create(person); // 创建一个继承自 person 的新对象

me.name = 'Matthew'; // 在新对象上设置属性
me.isHuman = true;

me.printIntroduction(); // 输出: "My name is Matthew. Am I human? true"

# 使用new操作符实现Object.create的方法

上面使用 Object.create 方法实现 new,而手写 Object.create 方法也可以用 new 去实现,

Object.mycreate = function (proto, properties) {
  function InnerObj() {}
  InnerObj.prototype = proto;
  if (properties) {
    Object.defineProperties(InnerObj, properties);
  }
  return new F();
};

# 使用 [Reflect.construct()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect/construct) 实现自定义 new 操作符

Reflect.construct() 方法与 new 操作符的行为类似,相当于运行 new target(...args)。这个方法也可以用于实现自定义的 new 操作符。例如:

function OneClass() {
  this.name = 'one';
}

function OtherClass() {
  this.name = 'other';
}

// 使用 Reflect.construct() 创建一个对象
var obj1 = Reflect.construct(OneClass, [], OtherClass);

// 等价于使用 Object.create() 创建一个对象并调用构造函数
var obj2 = Object.create(OtherClass.prototype);
OneClass.apply(obj2, []);

你还可以将上面手写的 newFactory 方法改成使用 Reflect.construct() 的方式:

function newFactory(ctor, ...args) {
  if (typeof ctor !== 'function') {
    throw new Error('The first parameter of newFactory must be a function');
  }

  let res = Reflect.construct(ctor, args); // 调用构造函数
  let isObject =
    typeof res === 'object' && res !== null && !(res instanceof Function);

  return isObject || typeof res === 'function' ? res : obj;
}

总之,理解 new 操作符的原理以及使用 Object.createReflect.construct() 可以帮助我们更好地理解 JavaScript 中的对象创建和继承机制。