前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库new 调用函数内部步骤 this 绑定
JavaScript函数与作用域

new 一个函数时,内部到底做了哪几步?this 指向谁?

new Foo() 做了四件事:新建一个空对象;把这个对象的原型指向 Foo.prototype;把它当作 this 执行 Foo;如果 Foo 没有返回一个对象,就把这个新对象作为结果返回。所以构造函数里的 this 就是正在创建的实例。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#函数与作用域
先看核心答案读代码示例
理解线索

`new` 的四个步骤

  1. 创建并连原型新建一个对象,原型设为 Foo.prototype,实例因此能用原型上的方法
  2. 绑定 this 执行以新对象为 this 调用 Foo,给 this 加的属性都落在实例上
  3. 决定返回值Foo 返回了对象或函数就用它,否则返回第一步建的对象

原型上的方法不会复制到实例上,所有实例共用一份。之后改了 Foo.prototype 上的方法,已经创建的实例也会受影响。

核心回答

先记住这个答案

用 new 调用函数时,引擎会做四步。第一步,创建一个新的空对象。第二步,把这个对象的原型(也就是 __proto__)指向构造函数的 prototype。第三步,把这个对象当作 this 去执行构造函数,构造函数里给 this 加的属性都加到了这个对象上。第四步,如果构造函数自己返回了一个对象,new 的结果就是那个对象;如果没写 return 或者返回的是数字、字符串这类原始值,结果就是第一步创建的新对象。

  • 实例的原型指向构造函数的 prototype
  • 构造函数里的 this 是新建的实例
  • 返回对象会替换实例,返回原始值被忽略
  • 箭头函数和对象方法简写不能 new

手写一个 new

面试里这道题的标准动作是手写 myNew,四步正好对应四行代码。

四步对应的代码JavaScript
function myNew(Ctor, ...args) {
  const obj = Object.create(Ctor.prototype) // 1、2:建对象并连上原型
  const result = Ctor.apply(obj, args) // 3:以 obj 为 this 执行
  const isObject = result !== null && (typeof result === 'object' || typeof result === 'function')
  return isObject ? result : obj // 4:返回了对象就用它,否则用 obj
}

function User(name) {
  this.name = name
}
User.prototype.greet = function () {
  return `Hi ${this.name}`
}
function Weird() {
  this.a = 1
  return { b: 2 } // 返回了一个对象
}

const u = myNew(User, 'Ada')
console.log(u.greet(), u instanceof User)
console.log(JSON.stringify(new Weird()), JSON.stringify(myNew(Weird)))
查看输出与解释
Hi Ada true
{"b":2} {"b":2}

Object.create(Ctor.prototype) 一步完成了「建对象」和「连原型」,所以 u 能调用原型上的 greet,instanceof 也成立。Ctor.apply(obj, args) 把新对象作为 this 传进去,this.name = name 就写到了 u 上。 Weird 演示了第四步的例外:它返回了 { b: 2 },原生 new 和手写版都丢掉了带 a 的那个实例,直接用返回的对象。判断条件要注意 null,typeof null 是 'object',但返回 null 时 new 仍然返回新建的实例。

this 在构造调用里为什么优先级最高

普通函数的 this 看怎么调用,new 是其中优先级最高的一种。哪怕函数已经用 bind 绑死了 this,用 new 调用时绑定的 this 也会被忽略,this 仍然是新创建的实例,只有 bind 预置的参数还保留。

忘了写 new 会怎样
构造函数就是个普通函数,不写 new 也能调用,这时它按普通调用处理。非严格模式下 this 是全局对象,this.name = name 会悄悄创建一个全局变量;严格模式下 this 是 undefined,给它赋属性直接抛 TypeError。ES6 的 class 不允许这种情况,不写 new 调用会直接抛 TypeError。
哪些函数不能 new
只有带「构造能力」的函数才能 new。普通函数声明、函数表达式和 class 可以;箭头函数、对象方法简写、async 函数和生成器函数都不行,new 它们会抛 TypeError。简单的判断方法是看它有没有 prototype 属性,箭头函数和方法简写都没有。生成器函数是个例外,它有 prototype,但照样不能 new。
回答前,多想一步

容易答错的地方

以为 prototype 上的方法会复制到每个实例
实例上只有构造函数里用 this.xxx 加的属性,原型上的方法是通过原型链找到的,所有实例共用同一个函数。这也是方法要写在 prototype 上而不是构造函数里的原因,写在构造函数里每个实例都会各生成一份。
手写 new 时只判断 typeof result === 'object'
这样会漏掉两个情况:返回 null 时会错误地返回 null,返回函数时又会错误地忽略它。原生 new 的规则是「返回值是对象或函数就用它」,null 不算对象。
试着用自己的话回答

面试官还会怎么问?

Object.create 和 new 有什么区别?

Object.create(proto) 只做「建对象、连原型」这一步,不执行任何构造函数。new 在此基础上还会执行构造函数、处理返回值。所以手写 new 时可以用 Object.create 完成前两步。

如果 Foo.prototype 被改成了一个原始值会怎样?

新对象的原型会退回到 Object.prototype,因为原型只能是对象或 null。这时实例 instanceof Foo 的判断还会直接抛 TypeError,因为 instanceof 要求右边的 prototype 是对象。

怎么让函数被直接调用时也自动 new?

在函数开头判断 new.target:普通调用时它是 undefined,这时 return new Foo(...arguments) 就行。以前没有 new.target 时用 this instanceof Foo 判断,但它能被 Foo.call(实例) 骗过去,不如 new.target 准确。

从一道题,走向一组知识

把知识连起来

函数与作用域

箭头函数的 this 指向谁?为什么 call 和 bind 改不了它?

箭头函数没有自己的 this,也就没法当构造函数,new 一个箭头函数会直接抛 TypeError。

函数与作用域

箭头函数里读 arguments,读到的是谁的?

箭头函数既没有 arguments 也不能 new,两点都说明它不创建自己的调用上下文。

放回知识体系中复习JavaScript 进阶知识

参考资料

  • new

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 手写一个 new
  3. this 在构造调用里为什么优先级最高
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑