60 秒回答模板

new 的执行流程可以按四步回答:创建一个新对象;把新对象的原型指向构造函数的 prototype;用这个新对象作为 this 执行构造函数并传入参数;根据构造函数返回值决定结果。如果构造函数显式返回对象或函数,new 表达式返回这个引用值;如果返回基本类型或没有返回值,就返回最初创建的新对象。手写 myNew 时可以用 Object.create(Constructor.prototype) 创建实例,再用 apply 执行构造函数,最后判断返回值是不是引用类型。

考点 原型链与 this 绑定
难度 前端高频手写题
回答目标 说清流程并写出 myNew

深入解析

01

先说 new 的产物

new 不是简单调用函数,而是创建一个能通过原型链访问构造函数 prototype 的实例对象,并把构造函数内部的 this 绑定到这个实例上。

02

原型绑定决定方法查找

实例本身通常只放实例属性,共享方法放在 Constructor.prototype 上。new 建立实例到 prototype 的原型链接,所以实例可以沿原型链找到方法。

03

this 绑定决定属性写入位置

构造函数执行时,this 指向新对象。构造函数里写 this.name = name,本质是在新对象上添加或修改实例属性,而不是写到全局对象或 prototype。

04

返回值规则是手写关键

构造函数返回对象或函数时,new 的结果会被这个返回值替代;返回 string、number、boolean、symbol、bigint、null、undefined 时,会忽略该返回值,仍返回实例。

05

边界要区分可构造函数

箭头函数没有自己的 this,也没有可用于构造的 prototype,不能被 new。class 必须通过 new 调用,直接用 apply 模拟 class 构造会报错,面试手写通常针对普通函数构造器。

javascript

实现一个最小版 myNew

function myNew(Constructor, ...args) {
  if (typeof Constructor !== "function") {
    throw new TypeError("Constructor must be a function");
  }

  const instance = Object.create(Constructor.prototype);
  const result = Constructor.apply(instance, args);
  const isObject = result !== null && (typeof result === "object" || typeof result === "function");

  return isObject ? result : instance;
}
  • Object.create(Constructor.prototype) 对应 new 的原型绑定步骤。
  • apply(instance, args) 对应构造函数内部 this 指向新实例。
  • 最后的引用类型判断用于覆盖构造函数显式 return 对象或函数的规则。

易错点

  • 只说 new 会创建对象,不说原型链如何连接到 Constructor.prototype。
  • 手写实现直接 Constructor(...args),导致 this 绑定错误。
  • 漏掉构造函数显式返回对象或函数时要返回该对象。
  • 把 __proto__ 当成首选实现方式,忽略 Object.create 更清晰也更稳定。

面试官追问

箭头函数为什么不能被 new?

箭头函数没有自己的 this 绑定,也没有作为构造器使用的 prototype,因此没有 [[Construct]] 能力,不能创建实例。

构造函数返回 null 会发生什么?

null 虽然 typeof 是 object,但不是有效引用返回值。new 会忽略它,返回创建出来的实例对象。

Object.create 和直接 {} 的区别是什么?

{} 的原型默认是 Object.prototype;Object.create 可以显式指定原型。手写 new 需要把实例原型指定为 Constructor.prototype。

bind 后的函数再 new,this 指向谁?

new 绑定优先于 bind 指定的 this。用 new 调用绑定函数时,this 指向新实例,但 bind 预置的参数仍然会参与调用。