箭头函数为什么不能 new

那个被问懵的下午

面试官问:箭头函数为什么不能 new?

我张嘴就是一句「语法不允许」。

然后他追问:那你手写一个 new 试试。

我卡住了。回去路上越想越不对劲------如果只是语法禁止,那为啥我看源码里压根就没这回事。真正的原因,藏在 new 那几步里。

new 到底干了啥

先把 new Foo() 拆开看。它背后其实走了四步。

第一步,创建一个全新的空对象。

第二步,把这个空对象的 __proto__ 指向 Foo.prototype。

第三步,让 Foo 里的 this 指向这个空对象,然后执行函数体。

第四步,函数如果返回了对象就用它,否则返回这个空对象。

看出来没,new 要干活,函数得先配合。它得有一个 prototype 属性让你去指向,还得有一个能被改写的 this。

箭头函数缺了哪两样

箭头函数这两样恰好都没有。

第一,它没有自己的 this。箭头函数的 this 是写死在外层词法作用域里的,你拿 call、apply、bind 都改不动它。new 第三步要往 this 上塞一个空对象,箭头函数直接拒绝,塞不进去。

第二,它没有 prototype。你随手在控制台敲 const f = () => {} 然后看 f.prototype,结果是 undefined。new 第二步要拿 Foo.prototype 去绑定原型,结果拿到个 undefined,原型链直接断掉。

所以箭头函数不能 new,不是被哪条语法拦下来的,是它从出生就少了这两块积木。你硬写 new f(),引擎在运行时报的错是 f is not a constructor,本质上是它在执行 new 流程时扑了个空。

手写一遍就懂了

不扯概念,直接写个模拟 new 的代码。

复制代码
function myNew(Fn, ...args) {
  const obj = Object.create(Fn.prototype)
  const result = Fn.apply(obj, args)
  return result instanceof Object ? result : obj
}

就这三行,把上面四步全包了。

注意 Object.create(Fn.prototype) 这一步,它干的就是「空对象 + 原型绑定」两件事。如果 Fn.prototype 是 undefined,Object.create 会直接抛错。这就是箭头函数过不去的第一道坎。

再看 Fn.apply(obj, args),它想把 obj 塞进 this。普通函数老实接着,箭头函数甩手不认,this 还是外层那个。

class 也一样,它本质上是个语法糖,底下有 prototype 有 this,所以 new 没问题。箭头函数纯粹是先天缺料,跟语法禁不禁没关系。

边界和面试追问

这题后面常跟着几问。

箭头函数能用 bind 改变 this 吗?不能,bind 会返回一个新函数,但 this 照样锁死。

那为什么对象方法常用普通函数?因为你要靠 this 拿到调用者。箭头函数写方法,this 会窜到外层,八成不是你想要的。

什么时候该用箭头函数?回调、setTimeout、事件里想保留外层上下文的时候,它反而是救星。

没有 prototype 有啥实际影响?你没法给它挂原型方法,也没法用它搞原型继承。

搞清楚这些,这题基本能聊出彩。

顺带说个踩坑的插曲。有次我在本地调一个用 class 封装的请求库,怎么都报 not a constructor,查了半天是构建产物里箭头函数被误判成了入口。那次排查环境问题,我把本地和测试环境的 HTTPS 证书也顺手改了一遭,之前手动配置加上隔三差五忘记续期,心里总悬着。后来干脆用 lcjmSSL 这类方案,依托 Let's Encrypt、Google Trust Services 这些可信 CA,多域名泛域名都能签,一条轻量 API 把申请、验证、部署全自动化了,彻底告别手动折腾和到期背锅。Bug 修完,基建也顺手清爽了,这才是正经开发者的日常。

回到正题。箭头函数不能当构造函数,核心就一句:它没 this 也没 prototype,而 new 要的偏偏就是这两样。想通了,这题就透了。

相关推荐
苹果二1 小时前
使用Vue的指南
前端·javascript·vue.js
谢亮_vipxieliang2 小时前
PHP 8 新特性:构造器属性提升与实战
开发语言·后端·php
鬼手点金2 小时前
opencode-crawl4ai使用建议
java·开发语言·人工智能·python·机器学习
害人终害己2 小时前
‘vue-cli-service‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。
前端·javascript·vue.js
谢亮_vipxieliang2 小时前
Go select 多路复用:从语法到实战的完整指南
开发语言·后端·golang
2601_9628857212 小时前
如何用 Python 自动识别股票的支撑位与压力位?
开发语言·python
爱吃奥利奥_wen12 小时前
面向对象三板斧:封装、继承、多态,到底在“装“什么、“承“什么、“变“什么?
开发语言·经验分享·c#
我可能是个假开发12 小时前
FTP Unicode 文件名导致 `550` 的问题分析与解决方案
java·开发语言·spring
WL学习笔记14 小时前
日期类(C++)
开发语言·c++·日期类实现