最后
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
大厂面试问深度,小厂面试问广度,如果有同学想进大厂深造一定要有一个方向精通的惊艳到面试官,还要平时遇到问题后思考一下问题的本质,找方法解决是一个方面,看到问题本质是另一个方面。还有大家一定要有目标,我在很久之前就想着以后一定要去大厂,然后默默努力,每天看一些大佬们的文章,总是觉得只有再学深入一点才有机会,所以才有恒心一直学下去。
前言
这是一道非常经典的面试题,涵盖了从函数的基本概念、运算符优先级,到作用域链、原型链、this关键字、new关键字等基础知识点考察,可以说能完整答对 JS 基础才算过了关,本文就带大家回顾并剖析这道面试题,应该是全网最详细的文章了,这次彻底搞懂它。
// a
function Foo () {
getName = function () {
console.log(1);
}
return this;
}
// b
Foo.getName = function () {
console.log(2);
}
// c
Foo.prototype.getName = function () {
console.log(3);
}
// d
var getName = function () {
console.log(4);
}
// e
function getName () {
console.log(5);
}
复制代码
按顺序执行后分别输出什么?
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
先自己尝试写出结果再看答案,后面是详细解析。
答案
Foo.getName(); // 2
getName(); // 4
Foo().getName(); // 1
getName(); // 1
new Foo.getName(); // 2
new Foo().getName(); // 3
new new Foo().getName(); // 3
复制代码
解析
1. Foo.getName()
这一问首先考察的是函数的基本概念:在 JS 中函数是第一类对象,也被称作"一等公民",这是因为函数拥有对象所拥有的全部功能。所以这里的 Foo.getName()
可以看作是调用了 Foo
对象上的属性,在题目中的 b 处有其定义,故结果输出 2 。
2. getName()
这里调用的 getName
在上下文中被定义了两次,一次是通过变量声明,一次是函数声明,故这一问考察的是变量声明提升与函数声明提升,声明提前会让声明提升到代码的最上层,而函数再一次发挥了它"一等公民"的特权:函数声明提升比变量声明提升更高,所以这一问实际执行代码可看作:
function getName() {
console.log(5);
};
var getName;
getName = function () {
console.log(4);
};
复制代码
两者声明共同提升之后,变量的赋值操作最后执行,所以调用 getName()
输出的结果是 4 。
3. Foo().getName()
和第一问相比看似只多了个括号,实际考察的内容完全不一样。
我们先复习一下 JS 中的运算符优先级,这是下来全部解题的基础。
首先成员访问运算从左到右执行,所以我们要先看 Foo()
函数做了什么,根据题目 a 处的定义:
function Foo () {
getName = function () {
console.log(1);
}
return this;
}
复制代码
执行 Foo()
之后为 getName
赋值一个函数(注意这里的 getName
并没有 var
关键字,所以还考察了作用域链的知识点),JS 在遇到未声明的变量时会向上一级一层层查找,前面我们知道了变量声明会提升,在全局作用域下 getName
是已经被声明的了,所以执行 Foo()
的作用其实就是把全局的 getName
又赋值了新函数。
而 Foo()
本身返回了 this
,所以这一问又变成了「this.getName()
输出什么?」。这里当然也就考察了 this 关键字 的知识点,这里在全局上下文执行,this
指代window
,也就是调用了 getName()
,执行结果是前面 Foo()
赋予的新函数,所以输出了 1 。
4. getName()
由于题目条件是顺序执行,所以这里经过了第三问之后全局 getName
已经被修改过了,在上一问已经解析完,这里毫无疑问执行输出是 1 。
5. new Foo.getName()
乍一看以为是要考察 new 关键字 了,其实并没有,它还是考察了上面提到的运算符优先级,根据优先级我们可以得出,Foo.getName()
是会先执行的,执行完只是输出了第一问的结果,再对其执行 new
没有意义,最后输出的还是 2 。
6. new Foo().getName()
这里开始考察 new 关键字 的概念,但我们还是要先说说这一问涉及的运算符优先级问题,可能你看过其它文章解析这一问的时候会说等价于 (new Foo()).getName()
,可你知道为什么会是这样吗?为什么第 5 问是先执行 Foo.getName()
而这一问却是先执行 new Foo()
呢?
这是因为 new
运算在优先级上有两种形式:
- 带参数列表:
new … ( … )
优先级 18 - 无参数列表:
new …
优先级 17
如果优先级不同那么按优先级最高的运算符先执行,不用考虑结合性。
跳槽是每个人的职业生涯中都要经历的过程,不论你是搜索到的这篇文章还是无意中浏览到的这篇文章,希望你没有白白浪费停留在这里的时间,能给你接下来或者以后的笔试面试带来一些帮助。
也许是互联网未来10年中最好的一年。WINTER IS COMING。但是如果你不真正的自己去尝试尝试,你永远不知道市面上的行情如何。这次找工作下来,我自身感觉市场并没有那么可怕,也拿到了几个大厂的offer。在此进行一个总结,给自己,也希望能帮助到需要的同学。
面试准备
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
面试准备根据每个人掌握的知识不同,准备的时间也不一样。现在对于前端岗位,以前也许不是很重视算法这块,但是现在很多公司也都会考。建议大家平时有空的时候多刷刷leetcode。算法的准备时间比较长,是一个长期的过程。需要在掌握了大部分前端基础知识的情况下,再有针对性的去复习算法。面试的时候算法能做出来肯定加分,但做不出来也不会一票否决,面试官也会给你提供一些思路。