「前端」震惊!一道代码输出题竟然牵扯出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
总结
一段小小的代码输出题,竟然能在三个运行时有三种不同的行为,真是让我打开眼界,当时面试官也没说是什么运行时下的运行结果,是不是也有些不严谨了🤣
#阿里云##前端##秋招#


阿里云工作强度 694人发布