2024年中级前端笔试面试题总结(含答案解析)

2301_79099606 2024-07-22 10:03:01 阅读 97

先按顺序执行同步任务,Promise新建后立即执行输出2,接着输出4,异步任务等同步任务执行完后执行,且同一次事件循环中,微任务永远在宏任务之前执行。这时候执行栈空了,执行事件队列,先取出微任务,输出3,最后取出一个宏任务,输出1。

6、for循环中的作用域问题(考察频率:高)

写出以下代码输出值,尝试用es5和es6的方式进行改进输出循环中的i值。

for (var i=1; i<=5; i++) {

setTimeout(function timer() {

console.log(i);

}, i*1000);

}

输出5个6,因为回调函数在for循环之后执行,所有函数共享一个i的引用。

es5:

for (var i=1; i<=5; i++) {

(function(j) {

setTimeout(function timer() {

console.log(j);

}, j*1000);

})(i);

}

es6:

for (let i=1; i<=5; i++) {

setTimeout(function timer() {

console.log(i);

}, i*1000);

}

7、闭包的作用(考察频率:中)

闭包的目的是外部函数可以访问内部函数的作用域(局部作用域)。比如访问到内部作用域的变量。

8、原型及原型链(考察频率:中)

原型的理解

所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(null除外)

所有的引用类型(数组、对象、函数),都有一个__proto__属性,属性值是一个普通的对象

所有的函数,都有一个prototype属性,属性值也是一个普通的对象

所有的引用类型(数组、对象、函数),__proto__属性值指向它的构造函数的prototype属性值

原型链的理解

一段代码如下:

// 构造函数

function Foo(name, age) {

this.name = name

}

Foo.prototype.alertName = function () {

alert(this.name)

}

// 创建示例

var f = new Foo(‘zhangsan’)

f.printName = function () {

console.log(this.name)

}

// 测试

f.printName()

f.alertName()

f.toString()

因为f本身没有toString(),并且f.proto(即Foo.prototype)中也没有toString。当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找。

如果在f.__proto__中没有找到toString,那么就继续去f.proto.__proto__中寻找,因为f.__proto__就是一个普通的对象而已嘛!

f.__proto__即Foo.prototype,没有找到toString,继续往上找 f.proto.__proto__即Foo.prototype.proto。Foo.prototype就是一个普通的对象,因此Foo.prototype.__proto__就是Object.prototype,在这里可以找到toString。 因此f.toString最终对应到了Object.prototype.toString 这样一直往上找,你会发现是一个链式的结构,所以叫做“原型链”。如果一直找到最上层都没有找到,那么就宣告失败,返回undefined。最上层是什么 —— Object.prototype.proto === null

9、重绘和回流(考察频率:中)

重绘:当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。

回流:当Render Tree(DOM)中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。

回流要比重绘消耗性能开支更大。

回流必将引起重绘,重绘不一定会引起回流。

参考:juejin.im/post/684490…

10、实现一个深拷贝(思路)(考察频率:中)

对象中可能又存在对象,所以需要深拷贝。首先需要知道这是一个递归调用,然后要判断一些特殊类型(数组,正则对象,函数)进行具体的操作,可以通过Object.prototype.toString.call(obj)进行判断。

参考:juejin.im/post/684490…

11、js浮点数运算精度问题(0.1+0.2!==0.3)

比如在 JavaScript 中计算 0.1 + 0.2时,到底发生了什么呢?

首先,十进制的0.1和0.2都会被转换成二进制,但由于浮点数用二进制表达时是无穷的,例如。

JavaScript 代码:

0.1 -> 0.0001100110011001…(无限)

0.2 -> 0.0011001100110011…(无限)

IEEE 754 标准的 64 位双精度浮点数的小数部分最多支持 53 位二进制位,所以两者相加之后得到二进制为:

JavaScript 代码: 0.0100110011001100110011001100110011001100110011001100

因浮点数小数位的限制而截断的二进制数字,再转换为十进制,就成了 0.30000000000000004。所以在进行算术计算时会产生误差。

浏览器相关

12、浏览器从加载到渲染的过程,比如输入一个网址到显示页面的过程。 (考察频率:高)

加载过程:

浏览器根据 DNS 服务器解析得到域名的 IP 地址

向这个 IP 的机器发送 HTTP 请求

服务器收到、处理并返回 HTTP 请求

浏览器得到返回内容

渲染过程:

根据 HTML 结构生成 DOM 树

根据 CSS 生成 CSSOM

将 DOM 和 CSSOM 整合形成 RenderTree

根据 RenderTree 开始渲染和展示

遇到

13、浏览器缓存机制(策略)(考察频率:中)

参考:segmentfault.com/a/119000000…

14、性能优化(考察频率:中)

优化的方向有两个:

减少页面体积,提升网络加载

优化页面渲染

减少页面体积,提升网络加载

静态资源的压缩合并(JS 代码压缩合并、CSS 代码压缩合并、雪碧图)

静态资源缓存(资源名称加 MD5 戳)

使用 CDN 让资源加载更快

优化页面渲染

CSS 放前面,JS 放后面

懒加载(图片懒加载、下拉加载更多)

减少DOM 查询,对 DOM 查询做缓存

减少DOM 操作,多个操作尽量合并在一起执行(DocumentFragment)

事件节流

尽早执行操作(DOMContentLoaded)

使用 SSR 后端渲染,数据直接输出到 HTML 中,减少浏览器使用 JS - 模板渲染页面 HTML 的时间

Vue

15、组件通信方式 (考察频率:高)

1)父->子

props(v-bind)

$refs

2)子->父

events(v-on)

$parent $root

3)非父子组件

event bus

vuex

16、双向绑定原理(考察频率:高)

网上各种文章很多,原理可以讲浅也可以讲深,看面试官自己的了解程度和他想考察的深度。 最基本的要讲清楚数据劫持Object.defineProperty(), 讲清楚依赖收集(Watcher、Dep)。

参考: 1、 juejin.im/post/684490…

2、juejin.im/post/684490…

17、路由导航钩子(导航守卫)(考察频率:中)

全局钩子

路由独享钩子

组件内钩子

看文档:router.vuejs.org/zh-cn/advan…

18、v-if和v-show的共同点和区别(考察频率:中)

参考官方文档

都是用来做条件渲染,通过条件控制元素的显示与隐藏。

v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。

v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。

一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

19、说说vue的双向数据绑定实现原理(考察频率:中)

通过Object.definerProperty来劫持各个数据的属性的setter和getter,在数据变化时,发布消息给依赖收集器,通知观察者去执行回调函数,达到视图更新的效果。(但是使用Object.definerProperty实现监听时是有一些痛点的,比如,①无法监测数组下标变化,导致数组删除或者插入元素时,数组的变化无法实时响应;②只能对对象的属性进行监测,当对象深度比较深时,只能遍历每个属性来实现监听。vue3.0采用的Proxy,就完全避开了Object.definerProperty方法的这些痛点)

20、说一下vue的生命周期(考察频率:高)

beforeCreate:初始化事件,进行数据观测。

created:data数据进行绑定。

beforeMount:虚拟DOM替换真实DOM。

mounted:将DOM元素挂载到页面。

beforeUpdate: data数据更新之前。

updated: data数据更新完成之后。

beforeDestroy:在实例销毁之前调用,所有实例仍可以调用。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

你要问前端开发难不难,我就得说计算机领域里常说的一句话,这句话就是『难的不会,会的不难』,对于不熟悉某领域技术的人来说,因为不了解所以产生神秘感,神秘感就会让人感觉很难,也就是『难的不会』;当学会这项技术之后,知道什么什么技术能做到什么做不到,只是做起来花多少时间的问题而已,没啥难的,所以就是『会的不难』。

我特地针对初学者整理一套前端学习资料分享给大家,戳这里即可领取

前端路线图

Uf-1712390237431)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

你要问前端开发难不难,我就得说计算机领域里常说的一句话,这句话就是『难的不会,会的不难』,对于不熟悉某领域技术的人来说,因为不了解所以产生神秘感,神秘感就会让人感觉很难,也就是『难的不会』;当学会这项技术之后,知道什么什么技术能做到什么做不到,只是做起来花多少时间的问题而已,没啥难的,所以就是『会的不难』。

我特地针对初学者整理一套前端学习资料分享给大家,戳这里即可领取

[外链图片转存中…(img-y9E3bsLZ-1712390237431)]

vue.js的36个技巧



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。