「前端」震惊!一道代码输出题竟然牵扯出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()
Foo.getName()
: 2,没什么好说的,调用的是 Foo 的静态方法,输出 2getName()
: 4- 除了
var
有变量提升以外,function
也有变量提升,而且function
是将整个声明+初始化提升到顶部,而非像var
一样将声明提升到顶部,但初始化留在原地 - 所以实际上是先声明了
function getName()
,然后又被var
留在原地的初始化覆盖了,故输出为 4
- 除了
Foo().getName()
:1- 这里首先调用
Foo()
,这个函数体内访问到的getName
变量实际上就是外部的getName
,将其覆盖为了输出 1,即window.getName = function () {console.log(1)}
- 然后返回
this
,由于没有使用new
来调用这个函数,这个this
实际上就是window
- 那这个调用就变成了
this.getName()
,也就是window.getName()
,即输出 1
- 这里首先调用
getName()
:1- 同理,之前的函数调用已经修改了全局的
getName
方法,所以输出还是 1
- 同理,之前的函数调用已经修改了全局的
new Foo.getName()
:2- 实际上等同于
new (Foo.getName)()
,正常调用静态方法,虽然这个方法里没有用到 this,也不影响输出
- 实际上等同于
new Foo().getName()
: 3- 此时因为通过 new 调用了 Foo 的构造器构造了实例,访问到的是原型上的方法
new new Foo().getName()
: 3- 等同于
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
总结
一段小小的代码输出题,竟然能在三个运行时有三种不同的行为,真是让我打开眼界,当时面试官也没说是什么运行时下的运行结果,是不是也有些不严谨了🤣
#阿里云##前端##秋招#