阿里经典面向对象面试题升级版(推荐看)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 阿里经典面向对象面试题升级版(推荐看)

前言


此题目为几年前阿里首创,此题一出就制造了面试中"惨案"。该题有可能你能说出结果,但你未必能说清楚原因。


我查阅了部分关于此题的解析,好多就是迷迷糊糊就给讲完了,根本没抓住问题核心,因此阿包也献上一篇自己的理解,希望能为正确一方添加一票,这样大家搜索到正确频率又能提高一点。


下面是原版阿里真题和解析:


传送门: 阿里题目链接


题目


分析


该题目涉及到的知识非常多,比如: 作用域、预编译、原型与原型链、new、事件循环。

我们首先来分析一下,该题上半部分到底做了些什么:


  1. 定义 test 函数
  2. test 函数创建一个静态方法 test.getName
  3. test 函数创建一个实例方法 test.prototype.getName
  4. 定义全局变量 getName,程序运行后赋值为 函数
  5. 定义全局函数 getName
  6. test 函数内部给全局变量 getName 赋新值,返回值为 this


与原题目相比,当前题目加入了事件循环的知识, Promise.thensetTimeout 都是异步任务,前者是微任务,后者为宏任务。


解析


预编译


  1. 函数预编译四部曲和全局预编译三部曲
  2. 变量声明,声明提升函数声明,整体提升


GO: {
    test: fn,
    getName: function getName() { console.log(6); }
}
复制代码


test.getName()


执行 test 函数上的静态方法 test.getName ,打印 3,setTimeout 的回调插入事件队列中,等待同步任务执行完毕


getName()


getName 执行之前, getName 已经被重新赋值为 console.log(5) ,打印 5


test().getName()


  1. test() 执行全局的 test 函数,修改全局 getName 值; test() 函数执行为默认绑定,非严格模式 this 指向 window ,返回值为 window


GO: {
    test: fn,
    // 全局 getName 值修改
    getName: function() { 
        Promise.resolve().then(() => console.log(0))
        console.log(1);               
    };
}
复制代码


  1. test().getName() 相当于执行 window.getName() ,调用 GO 中的 getNamePromise.then 压入微任务队列,打印 1


getName()


执行全局函数 getName() ,打印 1Promise.then 压入微任务队列


(⭐)new 知识补充


在进行后面题目的解析时,先补充一点关于 new 运算符的知识。


首先咱们来看一下 MDN 中对 new 的描述,语法是:


new constructor[([arguments])]
复制代码


([arguments]) 意味着可以缺省,会存在 new constructor(...args)new constructor 两种模式,并且前者的运算优先级高于后者。更详细的优先级见下图:


image.png


从上图可以看到,部分优先级如下:new(带参数列表) = 成员访问 = 函数调用 > new(不带参数列表)


new test.getName()


根据上面的知识,表达式中自左向右共有三个运算符: new 不带参数列表、成员访问、函数调用。


优先级相同的运算符执行顺序自左向右,因此先执行成员访问,获取到 test 函数上的静态方法 getName


成员访问之后,表达式相当于变为 new (test.getName)()new 操作符由不带参数列表变为带参数列表,自左向右执行,把 test.getName 视为构造函数,生成对应实例。


new (test.getName)() 执行,打印 3setTimeout 回调压入宏任务队列。


new test().getName()


表达式运算符自左向右分别为: new 带参数列表、成员访问、函数调用


  1. 执行 new test(): new 绑定, this 指向实例。
  2. new 生成实例上没有 getName 属性,沿原型链查找到 test.prototype.getName 属性,打印 4


new new test().getName()


表达式运算符自左向右分别为: new 不带参数、new 带参数、成员访问、函数调用

因此表达式可以转化为如下形式: new((new test()).getName())


  1. new test().getName: 访问到 test.prototype.getName 属性
  2. new new test().getName(): 以 test.prototype.getName 为构造函数,打印 4


Promise.then


执行微任务队列里的 promise.then ,微任务队列中共有两次 promise.then ,打印 20


setTimeout


执行宏任务队列里的 setTimeout 回调函数,打印 22


答案


3
5
1
1
3
4
4
0
0
2
2
复制代码


往期精彩文章



后语


如果大家感觉此文对你有一些帮助,希望能点个赞,鼓励一下阿包,阿包会不断努力的。另外如果本文章有问题,或者对文章其中一部分不理解,都可以评论区回复我,我们来一起讨论,共同学习,一起进步!


相关文章
|
16天前
|
存储 关系型数据库 MySQL
阿里面试:为什么要索引?什么是MySQL索引?底层结构是什么?
尼恩是一位资深架构师,他在自己的读者交流群中分享了关于MySQL索引的重要知识点。索引是帮助MySQL高效获取数据的数据结构,主要作用包括显著提升查询速度、降低磁盘I/O次数、优化排序与分组操作以及提升复杂查询的性能。MySQL支持多种索引类型,如主键索引、唯一索引、普通索引、全文索引和空间数据索引。索引的底层数据结构主要是B+树,它能够有效支持范围查询和顺序遍历,同时保持高效的插入、删除和查找性能。尼恩还强调了索引的优缺点,并提供了多个面试题及其解答,帮助读者在面试中脱颖而出。相关资料可在公众号【技术自由圈】获取。
|
22天前
|
消息中间件 存储 canal
阿里面试:canal+MQ,会有乱序的问题吗?
本文详细探讨了在阿里面试中常见的问题——“canal+MQ,会有乱序的问题吗?”以及如何保证RocketMQ消息有序。文章首先介绍了消息有序的基本概念,包括全局有序和局部有序,并分析了RocketMQ中实现消息有序的方法。接着,针对canal+MQ的场景,讨论了如何通过配置`canal.mq.partitionsNum`和`canal.mq.partitionHash`来保证数据同步的有序性。最后,提供了多个与MQ相关的面试题及解决方案,帮助读者更好地准备面试,提升技术水平。
阿里面试:canal+MQ,会有乱序的问题吗?
|
18天前
|
消息中间件 架构师 Java
阿里面试:秒杀的分布式事务, 是如何设计的?
在40岁老架构师尼恩的读者交流群中,近期有小伙伴在面试阿里、滴滴、极兔等一线互联网企业时,遇到了许多关于分布式事务的重要面试题。为了帮助大家更好地应对这些面试题,尼恩进行了系统化的梳理,详细介绍了Seata和RocketMQ事务消息的结合,以及如何实现强弱结合型事务。文章还提供了分布式事务的标准面试答案,并推荐了《尼恩Java面试宝典PDF》等资源,帮助大家在面试中脱颖而出。
|
22天前
|
SQL 关系型数据库 MySQL
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
尼恩,一位40岁的资深架构师,通过其丰富的经验和深厚的技術功底,为众多读者提供了宝贵的面试指导和技术分享。在他的读者交流群中,许多小伙伴获得了来自一线互联网企业的面试机会,并成功应对了诸如事务ACID特性实现、MVCC等相关面试题。尼恩特别整理了这些常见面试题的系统化解答,形成了《MVCC 学习圣经:一次穿透MYSQL MVCC》PDF文档,旨在帮助大家在面试中展示出扎实的技术功底,提高面试成功率。此外,他还编写了《尼恩Java面试宝典》等资料,涵盖了大量面试题和答案,帮助读者全面提升技术面试的表现。这些资料不仅内容详实,而且持续更新,是求职者备战技术面试的宝贵资源。
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
|
22天前
|
Kubernetes 架构师 算法
阿里面试:全国14亿人,统计出重名最多的前100个姓名
文章介绍了如何解决“从全国14亿人的数据中统计出重名人数最多的前100位姓名”的面试题,详细分析了多种数据结构的优缺点,最终推荐使用前缀树(Trie)+小顶堆的组合。文章还提供了具体的Java代码实现,并讨论了在内存受限情况下的解决方案,强调了TOP N问题的典型解题思路。最后,鼓励读者通过系统化学习《尼恩Java面试宝典》提升面试技巧。
阿里面试:全国14亿人,统计出重名最多的前100个姓名
|
27天前
|
存储 缓存 NoSQL
阿里面试题:缓存的一些常见的坑,你遇到过哪些,怎么解决的?
阿里面试题:缓存的一些常见的坑,你遇到过哪些,怎么解决的?
|
22天前
|
存储 Kubernetes 架构师
阿里面试:JVM 锁内存 是怎么变化的? JVM 锁的膨胀过程 ?
尼恩,一位经验丰富的40岁老架构师,通过其读者交流群分享了一系列关于JVM锁的深度解析,包括偏向锁、轻量级锁、自旋锁和重量级锁的概念、内存结构变化及锁膨胀流程。这些内容不仅帮助群内的小伙伴们顺利通过了多家一线互联网企业的面试,还整理成了《尼恩Java面试宝典》等技术资料,助力更多开发者提升技术水平,实现职业逆袭。尼恩强调,掌握这些核心知识点不仅能提高面试成功率,还能在实际工作中更好地应对高并发场景下的性能优化问题。
|
2月前
|
缓存 监控 NoSQL
阿里面试让聊一聊Redis 的内存淘汰(驱逐)策略
大家好,我是 V 哥。粉丝小 A 面试阿里时被问到 Redis 的内存淘汰策略问题,特此整理了一份详细笔记供参考。Redis 的内存淘汰策略决定了在内存达到上限时如何移除数据。希望这份笔记对你有所帮助!欢迎关注“威哥爱编程”,一起学习与成长。
|
26天前
|
存储 算法 安全
HashMap常见面试题(超全面):实现原理、扩容机制、链表何时升级为红黑树、死循环
HashMap常见面试题:红黑树、散列表,HashMap实现原理、扩容机制,HashMap的jd1.7与jdk1.8有什么区别,寻址算法、链表何时升级为红黑树、死循环
|
3月前
|
Java 数据处理 开发者
【Java基础面试十二】、说一说你对面向对象的理解
这篇文章阐述了面向对象是一种以类和对象为基础,通过封装、继承和多态等概念来模拟现实世界中的事物及其相互关系的程序设计方法,它强调以事物为中心进行思考和系统构造,与结构化程序设计相比,更符合人类的自然思维方式。
【Java基础面试十二】、说一说你对面向对象的理解