「前端」震惊!一道代码输出题竟然牵扯出V8/Node的差异!

这是一道阿里云一面的代码输出题原题,笔者面试的时候直接就是抓耳挠腮,面试官甚至安慰我说你可以多看看,我看你已经痛苦面具了(可能也是因为笔者的面部表情比较丰富吧)

V8

function Foo() {
  getName = function () {
    console.log(1)
  }
  return this
}
Foo.getName = function () {
  console.log(2)
}
Foo.prototype.getName = function () {
  console.log(3)
}
var getName = function () {
  console.log(4)
}
function getName() {
  console.log(5)
}
Foo.getName()
getName()
Foo().getName()
getName()
new Foo.getName()
new Foo().getName()
new new Foo().getName()
  1. Foo.getName(): 2,没什么好说的,调用的是 Foo 的静态方法,输出 2
  2. getName(): 4
    1. 除了var有变量提升以外,function 也有变量提升,而且 function 是将整个声明+初始化提升到顶部,而非像 var 一样将声明提升到顶部,但初始化留在原地
    2. 所以实际上是先声明了 function getName() ,然后又被 var 留在原地的初始化覆盖了,故输出为 4
  3. Foo().getName() :1
    1. 这里首先调用 Foo() ,这个函数体内访问到的 getName 变量实际上就是外部的 getName ,将其覆盖为了输出 1,即 window.getName = function () {console.log(1)}
    2. 然后返回 this,由于没有使用 new 来调用这个函数,这个 this 实际上就是 window
    3. 那这个调用就变成了 this.getName(),也就是 window.getName() ,即输出 1
  4. getName() :1
    1. 同理,之前的函数调用已经修改了全局的 getName 方法,所以输出还是 1
  5. new Foo.getName() :2
    1. 实际上等同于new (Foo.getName)() ,正常调用静态方法,虽然这个方法里没有用到 this,也不影响输出
  6. new Foo().getName() : 3
    1. 此时因为通过 new 调用了 Foo 的构造器构造了实例,访问到的是原型上的方法
  7. new new Foo().getName(): 3
    1. 等同于 new ((new Foo()).getName)() ,又因为new Foo().getName = function(){console.log(3)} ,就又等同于new function(){console.log(3)}() ,即正常输出3

下面对我电脑上的两个运行时的报错进行分析

Node

Foo().getName is not a function

在 V8 中,全局对象是 window ,在 Node 中,全局对象是 global ,关键在于,V8 会把全局的 var/function 绑定到 window 对象上,而 Node 不会将其绑定到 global 上,这就造成了这里的global.getName 没有定义的问题

Bun

这是一个比较新的 js 运行时,官网说很快所以我本地运行的时候一般都会用这个,它在var getName = function () 这里产生了不一样的报错:

SyntaxError: Cannot declare a var variable that shadows a let/const/class variable: 'getName'.

说明 Bun 的设计者并不允许 var 变量去覆盖一个 function

总结

一段小小的代码输出题,竟然能在三个运行时有三种不同的行为,真是让我打开眼界,当时面试官也没说是什么运行时下的运行结果,是不是也有些不严谨了🤣

#阿里云##前端##秋招#
全部评论
大佬太牛了,一直跟你的面经
1 回复 分享
发布于 2024-08-29 18:53 河北
我靠,这跟我美团一面的手撕几乎一模一样
点赞 回复 分享
发布于 2024-08-29 19:38 浙江
感谢分享,67太搞了,谁会记得new关键字的优先级啊
点赞 回复 分享
发布于 2024-08-29 23:01 北京
关注佬佬
点赞 回复 分享
发布于 2024-08-29 23:55 浙江
是挺坑的,浏览器和nodejs实现很多地方不一致,我经常翻教程然后实践发现不是那样子……
点赞 回复 分享
发布于 2024-09-23 15:00 天津

相关推荐

04-02 18:36
已编辑
南京大学 Java
📍面试公司:字节👜面试岗位:后端开发⏳面试时长:1h📖面试问题:1. 自我介绍拷打项目2. 讲一下智能批改的工作流程具体是如何设计的?3. 在模型返回结果给前端或用户之前,是否进行了后处理操作,如何处理的?​4. 如果大模型出现幻觉(结果不符合预期),如何处理异常情况?5. 智能批改的线程池配置是怎样的?6. 线程池如果配置不合理会出现什么问题?​7. 若平台开放给全校使用,现有架构可能需要进行哪些调整?8. workflow超时或失效,有没有兜底方案?9. 微调工作简单说一下?10. 如何判断模型效果是不是有提升?(标准很模糊,不满意)11. 讨论其他网站的做法,问后续优化思路12. 数据集和训练集的来源和划分?转战后端开发内容13. MongoDB相比于MySQL的优势是什么?14. OSS是什么?用于什么?15. 如何保证MongoDB到OSS数据转存时的一致性?如果服务崩溃如何处理?16. Redis缓存内容的策略是什么?如何更新缓存?17. 讲一下策略模式18. 策略模式在项目重构中如何应用的?19. 另一个项目的算法了解一下零星八股20. MySQL索引失效情况21. IO流说一下? 二进制文件用什么?开放题22.Manus有没有了解过,如果优化自己的项目,该怎么做?🖊笔试问题:lc3 无重复字符的最小子串🙌面试体验:我的评价是准备了好久八股,屑屑。面试官人很好,不会打断说话,卡壳也不会为难#软件开发笔面经#
查看22道真题和解析 软件开发笔面经
点赞 评论 收藏
分享
03-23 23:18
门头沟学院
字节暑期实习 一面面经1. 自我介绍2.介绍实习做的东西,聊项目3.通用组件开发规范,组件的封装,函数的处理,props的设置...4.前端页面一些性能问题有没有办法做到前置的拦截(项目中聊到了排除和解决了两处内存泄漏的问题)5.面试官问我项目中还有没有她没问到的亮点(这让我怎么回答啊哈哈哈,面试官也笑了)6.CSS选择器优先级/权重顺序7.分析内部div的颜色,具体就是父子盒子,都带了ID和类选择器,判断内部的盒子是哪个颜色(权重相同,最后出现的样式生效)8.事件循环的概念9.微任务宏任务有哪些10.然后出了一道代码输出题,判断输出顺序11.数组有用过哪些方法12.filter是干嘛的,手撕filter方法13.在使用git的多人开发下,如何保证和其他人的代码不冲突,可以用什么指令(git rebase)14.实现模板字符串的输出15.反问总结: 一面面试官是个姐姐,人非常好,遇到有卡顿的地方会稍微给一些提示,没答对的地方会给反馈,让下去再看看,能知道哪些地方需要加强,面试体验非常棒二面凉经1.自我介绍2.介绍实习做的东西3.组件化是为了解决怎么样的问题,为什么我们要抽象出组件,在一个页面中写不好吗4.介绍自己项目的登录模块,具体的实现流程,返回的token能否携带用户信息?这个token存在了哪里5.http-only是干嘛用的6.常见的登录方案7.闭包的概念 -> 为什么要有闭包?它常驻在内存中不是会导致内存泄漏吗,这是为什么 -> 闭包在开发中实际的应用场景(节流,防抖) -> 实现节流8.事件循环的概念 -> 然后出了一道代码输出题,判断输出顺序 -> 哪些是微任务哪些是宏任务 -> 微任务和宏任务的优先级9.双向数据绑定的原理 -> defineProperty和proxy的区别,为什么vue3要用proxy -> proxy不需要递归遍历吗?10.defineProperty后续如果要添加对象,但因为一开始没观察到,但如果业务上确实需要新增一些属性,我们还想渲染视图的话应该怎么操作?(初始时设定,vue.set,数组的话可以用splice)11.虚拟dom12.用户输入url到页面渲染中间经历了哪些步骤?用了什么协议 响应回的HTML文件中,CSS和JS从哪弄13.dns和域名解析是一个东西吗14.实现事件订阅发布者模式(不会....)#牛客AI配图神器#总结: 面试体验一般,面试官面试过程总叹气(也不知道答对还是答错哈哈),搞的我也有点烦,也不会给反馈(虽然是正常的)。不过面试下来也是发现了自己很多的不足,继续学习
查看24道真题和解析
点赞 评论 收藏
分享
评论
15
37
分享

创作者周榜

更多
牛客网
牛客企业服务