当前位置: 首页 > 面试经验 >

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

优质
小牛编辑
67浏览
2024-08-29

「前端」震惊!一道代码输出题竟然牵扯出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

总结

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

#阿里云##前端##秋招#
 类似资料: