前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >这道JS经典面试题不要背,今天带你彻底搞懂它!

这道JS经典面试题不要背,今天带你彻底搞懂它!

原创
作者头像
茶无味的一天
发布于 2022-10-08 10:13:04
发布于 2022-10-08 10:13:04
49500
代码可运行
举报
文章被收录于专栏:品味前端品味前端
运行总次数:0
代码可运行

前言

这是一道非常经典的面试题,涵盖了从函数的基本概念、运算符优先级,到作用域链、原型链、this关键字、new关键字等基础知识点考察,可以说能完整答对 JS 基础才算过了关,本文就带大家回顾并剖析这道面试题,应该是全网最详细的文章了,这次彻底搞懂它。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 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);
}

按顺序执行后分别输出什么?

  1. Foo.getName();
  2. getName();
  3. Foo().getName();
  4. getName();
  5. new Foo.getName();
  6. new Foo().getName();
  7. new new Foo().getName();

先自己尝试写出结果再看答案,后面是详细解析。

答案

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 在上下文中被定义了两次,一次是通过变量声明,一次是函数声明,故这一问考察的是变量声明提升与函数声明提升,声明提前会让声明提升到代码的最上层,而函数再一次发挥了它"一等公民"的特权:函数声明提升比变量声明提升更高,所以这一问实际执行代码可看作:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function getName() {
    console.log(5);
};

var getName;

getName = function () {
    console.log(4);
};

两者声明共同提升之后,变量的赋值操作最后执行,所以调用 getName() 输出的结果是 4 。

3. Foo().getName()

和第一问相比看似只多了个括号,实际考察的内容完全不一样。

我们先复习一下 JS 中的运算符优先级,这是下来全部解题的基础。 -> MDN - 运算符优先级汇总表

首先成员访问运算从左到右执行,所以我们要先看 Foo() 函数做了什么,根据题目 a 处的定义:

代码语言:txt
AI代码解释
复制
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 运算在优先级上有两种形式:

  1. 带参数列表: new … ( … ) 优先级 18
  2. 无参数列表: new … 优先级 17

如果优先级不同那么按优先级最高的运算符先执行,不用考虑结合性。

比如 1 + 1 * 2 执行起来就是 1 + (1 * 2)

如果优先级相同则按结合性执行

比如赋值运算结合性是"从右到左",所以 a = b = 1 实际为 a = (b = 1)

所以这就解释了为什么这一问会是 new Foo() 先执行,我们画个图看下:

Description
Description

在上一问里成员访问优先级是18,new(无参列表)优先级是17,优先级不同,则高优先级先执行,所以上一问先执行 Foo.getName()

而这一问里 new(带参列表)优先级与成员访问同属18,优先级相同,并行下看结合性,new 带参时结合性不相关,所以直接执行,成员访问结合性从左到右,所以先拿出 Foo() 执行,于是得出了上面等价于 (new Foo()).getName() 的结论。

接下来就是考察 new 相关概念了,new Foo()Foo 为原型创建了一个新对象,这个实例本身并没有 geiName 这个方法,但是题目 c 处在 Foo 函数的原型上挂载过一个 getName 方法,最终实例会通过原型链访问到 Foo.prototype.getName() 这个方法,结果输出 3 。

复习 new 关键字做了什么:创建新对象并将 .__proto__ 指向构造函数的 .prototypethis 指向新创建的对象 返回新对象复习 原型链 知识点:每个函数实例对象都有一个 __proto__ 属性,__proto__ 指向了 prototype,当访问实例对象的属性或方法,会先从自身构造函数中查找,如果找不到就通过 __proto__ 去原型中查找。

7. new new Foo().getName()

考察的上一问其实已经讲完了,还是一样画张图:

所以得出实际执行的是:new(new Foo().getName())

new Foo().getName() 在上一问可知实例最终访问 Foo 原型链上的方法,最终为创建 new(Foo.prototype.getName()) 的实例返回,结果输出 3 。

以上就是文章的全部内容,希望对你有所帮助!,我是茶无味de一天,希望与你共同成长~

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
记Javascript一道题的理解
代码如下: 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
sam dragon
2018/01/17
5950
前端知识点杂集
解析: 很多人容易搞错第二个输出,因为使用 defineProperty 定义的属性默认是不可枚举的。
kif
2023/02/27
2290
前端知识点杂集
【宠粉通道】叫我讲解的一道前端JS面试题-灵魂三问:prototype?类的prototype是什么?对象的proto是什么
每个函数就是一个对象(Function),函数对象都有一个子对象 prototype对象,类是以函数的形式来定义的。prototype表示该函数的原型,也表示一个类的成员的集合。
达达前端
2020/01/02
4440
一道常被人轻视的web前端常见面试题(JS)
面试题是招聘公司和开发者都非常关心的话题,公司希望通过它了解开发者的真实水平和细节处理能力,而开发者希望能够最大程度地展示自己的水平(甚至超常发挥)。本文提供了众多前端开发面试题,无论是招聘方还是应聘方都值得一看!
用户7194797
2020/04/13
7680
前端同学经常忽视的一个 JavaScript 面试题
这几天面试上几次碰上这道经典的题目,特地从头到尾来分析一次答案,这道题的经典之处在于它综合考察了面试者的JavaScript的综合能力,包含了变量定义提升、this指针指向、运算符优先级、原型、继承、全局变量污染、对象属性及原型属性优先级等知识,此题在网上也有部分相关的解释,当然我觉得有部分解释还欠妥,不够清晰,特地重头到尾来分析一次,当然我们会把最终答案放在后面,并把此题再改高一点点难度,改进版也放在最后,方便面试官在出题的时候有个参考,更多详情可关注本文作者@Wscats
前端达人
2020/04/10
5070
前端同学经常忽视的一个 JavaScript 面试题
js烧脑面试题大赏
本文精选了20多道具有一定迷惑性的js题,主要考察的是类型判断、作用域、this指向、原型、事件循环等知识点,每道题都配有笔者详细傻瓜式的解析,偏向于初学者,大佬请随意。
街角小林
2022/06/15
3400
前端面试题“七连击”(一)
////////////////////// 这道“七连击”的前端面试题来自与Github上的一篇文章,已经火了很久。介于这道题很经典,考点还很多,所以在这里与大家分享。 格式化后的代码,看上去会舒服
用户1687375
2018/06/08
5790
20道精选的面试题附答案,进来看看能答对多少(二)
以下题目,本人验证无误,查阅了相关资料,得出解析部分并做了相关总结,希望对正准备跳槽或找工作的你有帮助!
前端达人
2021/06/16
5580
26道费脑子的 JavaScript 面试题整理,看看你能答对几道
今天为大家精选了26道稍微有点烧脑的JavaScript题,主要考察的是类型判断、作用域、this指向、原型、事件循环等知识点,每道题都配有笔者详细傻瓜式的解析,偏向于初学者,大佬请随意。
前端达人
2021/08/10
3770
26道费脑子的 JavaScript 面试题整理,看看你能答对几道
阿里前端一面必会面试题合集
需要注意的是最后一个定时器打印出的p1其实是.finally的返回值,我们知道.finally的返回值如果在没有抛出错误的情况下默认会是上一个Promise的返回值,而这道题中.finally上一个Promise是.then(),但是这个.then()并没有返回值,所以p1打印出来的Promise的值会是undefined,如果在定时器的下面加上一个return 1,则值就会变成1。
loveX001
2022/09/11
3400
2020年前端面试题集锦(奥利给!!!)
如果用一句话说明 this 的指向,那么即是: 谁调用它,this 就指向谁。但是仅通过这句话,我们很多时候并不能准确判断 this 的指向。因此我们需要借助一些规则去帮助自己:
Vam的金豆之路
2021/11/30
6560
闭包面试回答_ajax面试题
👸🏾:写在前面:在学习了闭包之后,试着做做这些题。其实是一种很棒地检验自己学习成果的手段。我当时反反复复,学了但好像又没完全学,遇到题还是一头雾水,到现在可以捋得很清楚也经历了蛮久的。而且从this,执行上下文,作用域一直走过来,这些题目涉及的内容也相对全面,加油喽。👍🏾 ​​​​​​​👉【JS基础整理—No.06】闭包_Chailo的博客-CSDN博客 //🍕 闭包面试题1 function show(){ f = function fn(){ console.log(x); } v
全栈程序员站长
2022/09/27
2070
【前端】:变量提升、this绑定、 优先级与关联性
Conceptually, for example, a strict definition of hoisting suggests that variable and function declarations are physically moved to the top of your code, but this is not in fact what happens. Instead, the variable and function declarations are put into memory during the compile phase, but stay exactly where you typed them in your code.
WEBJ2EE
2020/02/26
4990
前端面试题“七连击”(二)
////////////////////// 这道“七连击”的前端面试题来自与Github上的一篇文章,已经火了很久。介于这道题很经典,考点还很多,所以在这里与大家分享。 格式化后的代码,看上去会舒服
用户1687375
2018/06/08
7580
前端一面高频面试题(附答案)
我们常说的代理也就是指正向代理,正向代理的过程,它隐藏了真实的请求客户端,服务端不知道真实的客户端是谁,客户端请求的服务都被代理服务器代替来请求。
loveX001
2022/12/14
6340
工作中常用的javascript常识
JS 中分为七种内置类型,七种内置类型又分为两大类型:基本类型和对象(Object)。
前端迷
2019/12/05
5460
工作中常用的javascript常识
字节跳动最爱考的前端面试题:JavaScript 基础
JavaScirpt 使用 Number 类型来表示数字(整数或浮点数),遵循 IEEE 754 标准,通过 64 位来表示一个数字(1 + 11 + 52)
一只图雀
2021/03/03
1.5K0
字节跳动最爱考的前端面试题:JavaScript 基础
557 原型prototype和原型链__proto__:原理,函数的三种角色,for in,手写new
Object.create(xxx):创建一个空对象,并且让把xxx作为创建对象的原型(空对象.__proto __ = xxx),xxx必须是对象或者null,如果xxx是null,则创建一个没有任何原型指向的空对象
全栈程序员站长
2022/09/07
2230
557 原型prototype和原型链__proto__:原理,函数的三种角色,for in,手写new
美团前端面试题集锦_2023-02-28
因为浏览器对视频格式支持程度不一样,为了能够兼容不同的浏览器,可以通过source来指定视频源。
用户10377376
2023/02/28
1.1K0
那些年遇到的刁钻JavaScript面试题(可防踩坑)
解析: 这是比较常规的面试题了,主要考察的是 JavaScript 中的隐式类型转换。在 JS 中 + 主要有两个作用:数字相加和字符串拼接,当 + 两边不都为数字时会把它们都转为字符串再拼接,所以第一个 2 会先被转成 '2' 再与第二个 '2' 拼接。
MudOnTire
2020/07/26
7420
推荐阅读
相关推荐
记Javascript一道题的理解
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档