这个礼拜一直在面试,想着看看能否拿到不错的offer前去实习,从周一到周四,面了将近10家,特整理此份面经,希望对秋招的各位有所帮助
A公司
一面
面试官人很好,我回答的时候不会他会笑笑然后提醒我
自我介绍~
面试官简单问了下项目情况,也没继续深入~
js数据类型
接着又问了原始和引用类型的区别
let,const的区别
const之后的原始类型无法更改
js作用域
全局,函数,块级,eval欺骗词法~
针对小白的js作用域详细介绍 - 掘金 (juejin.cn)
谈谈作用域链
函数内访问变量是顺着作用域链查找的,从内往外,但是不能从外往内,这个链状是看函数的声明位置,声明在全局,就往全局找
es6的Promise
先答了Promise三种状态,pending,fulfilled,rejected,然后面试官问我状态可以逆转吗,不可逆,否则处理异步就不可靠了
Promise和async,await区别
Promise可以用.catch或者.then的第二个参数来捕获错误,async需要借助try,catch来捕获错误,async是通过Promise和generator打造的,generator相当于可以用next控制执行
ref和reactive区别
源码剖析ref和reactive的区别 - 掘金 (juejin.cn)
讲Proxy,依赖收集,依赖触发,类型判断,js对象的getter,setter~
如何调用父组件的函数
组件传参,通过事件或者props
场景题:给你一个类数组,就是key,value对这种,设计一个组件,通过vue去把这些数据渲染出来,不用考虑后端
聊了迭代类数组,父子组件传参,v-for,key
然后希望实现分页处理,每页数据只有10条
写两个点击函数,用计算属性实现,把数据弄成二维数组,如果是往具体页面增加数据就是将那页的数据提取出来进行操作
最后面试官跟我说是校友哈哈哈
二面
自我介绍+聊自己的掘金
diff算法
面试官直接拿我最近的文章问
详聊vue的diff算法 - 掘金 (juejin.cn)
聊项目,项目亮点
二叉树遍历
好久没刷算法题~
// 先序遍历 function preorder(root) { if(!root) return console.log(root.val) preorder(root.left) preorder(root.right) } // 中序遍历 function minorder(root) { if(!root) return minorder(root.left) console.log(root.val) minorder(root.right) } // 后序遍历 function backorder(root) { if(!root) return backorder(root.left) backorder(root.right) console.log(root.val) }
B公司
这家公司电话面……,很不喜欢电话面
解决异步的方式
回调,promise,generator,async,await,发布订阅……
vue数据更新,但是页面没有更新,你如何排查
考虑数据是否响应式、考虑数据更新在异步中,可以使用nextTick、也有可能数据被缓存了,考虑使用$set方法直接修改数据
使用vuex的注意点
vuex遵循单向数据流的原则,只能从state流向组件,修改state只能通过action或者mutation来修改,而不是直接拿到state进行修改,另外mutation是同步的操作,action可以包含异步操作,另外一般使用vuex是因为需要管理较大型的状态,对于简单的状态管理,建议直接父子,子父传参
介绍下vue3的生命周期
分为几个阶段,创建阶段,挂载阶段,更新阶段,销毁阶段,还有捕获错误的阶段。每个阶段都有对应的钩子函数去执行。然后问我一般用哪个钩子去发请求,我说用onMounted,因为有些数据拿到之后可能会操作dom
vue2和vue3响应式原理区别
- vue2是用得
Object.defineProperty
,vue3是用得Proxy,Proxy可以捕获更多类型的操作,更灵活 - vue3对ts的支持更友好,提供了更好的类型判断和错误提示
Object.defineProperty
的局限性
不能监听数组的变化,不能监听新增属性和删除属性,defineProperty
定义的属性不可以枚举,因此无法监听新增的属性或删除的属性,不能监听对象的深层属性,defineProperty
性能开销很大,
会用浏览器去打断点调试吗
我说我用过,但是用得很少,都是用log去打印调试的,因为一般打包工具会自动把无关代码剔除掉
C公司
自我介绍~
你有封装过组件吗,讲讲
聊得过程中谈到了插槽,就问我了作用域插槽
作用域插槽用过吗
作用域插槽允许子组件向父组件传递数据,需要在子组件v-bind绑定对应的数据,父组件通过slot-scope属性来接收传递的数据
xml
复制代码
<!-- 子组件 --> <template> <div> <slot :item="item"></slot> </div> </template> <!-- 父组件 --> <template> <child-component> <template v-slot:default="slotProps"> <p>{{ slotProps.item }}</p> </template> </child-component> </template>
盒模型
js闭包
面试官:聊聊js闭包。来看这篇,小白也能读懂!(内含调用栈及作用域链的详细讲解) - 掘金 (juejin.cn)
js判断数据类型
深入认识js四大常用数据类型判断,一次性带你搞明白(内含面试热点)! - 掘金 (juejin.cn)
event-loop
先执行同步,再执行微任务队列,最后执行宏任务,执行一次宏任务之前会清空掉微任务队列
== 和 === 的区别
== 判断的是值,并且比较时会进行类型转换,=== 判断类型是否一致,这种比较更严格,防止类型转换
es6的新特性
let,const,解构,箭头函数,set,map,WeakSet,WeakMap,Reflect,Promise,generator,async……
vue2和vue3响应式
vue生命周期
这个面试官跟我说请求数据一般放在beforeCreated
,因为onMounted得话,等dom加载完毕再去请求数据,会导致数据等待更长的时间才能展示
keep-alive
将组件缓存起来,像是页面固定的广告组件就可以用这个包裹,这样跳转路由时不需要重新渲染dom,并且还提供了两个钩子activated和deactivated,分别在缓存过的组件加载时和离开时触发
后面聊了聊项目难点,面试官自己介绍了公司的业务相关内容
D公司
自我介绍~
为什么选择前端
项目难点
session,cookie,localStorage的区别
三者都是web开发用于在客户端和浏览器端之间存储数据的机制,不过各有特点
存储:session存在服务器,cookie和localStorage存储在浏览器
生命周期:session与用户会话相关联,即用户打开浏览器和关闭浏览器的时间段,cookie可以设置过期时间,localStorage永久,除非显示删除
存储容量:session最大,cookie一般4Kb,用于存放登录令牌,localStorage一般5Mb
安全性:session安全性最高,因为存储在服务端,客户端无法直接访问,cookie和localStorage容易受到XSS和CSRF等安全攻击
总得来说,session适合存储敏感信息和大数据,安全性高,cookie适合存储少量数据,用于客户端和服务端之间的通信,localStorage适合存储持久化数据,cookie最大特征就是任意请求都会把cookie带上
大文件上传
将大文件分割成多个小块,然后逐个上传这些切片,最后在服务端将这些切片组合成完整的文件
追问:后端如何确保这个顺序
前端将文件切片时,为每个切片添加一个序号或者唯一标识符,上传到服务端时,将这些切片按照序号或标识符的顺序进行上传
koa框架相比较于其他的node框架有何优势
koa使用了基于Promise的中间件机制,相比较Express等框架更加轻量级和灵活,并且中间件的写法更加简洁明了,使用async,await避免回调地狱。
Koa提供了一个集中的错误处理机制,通过try,catch语法捕获异步错误
Koa允许开发者更细粒度地控制http请求和相应的过程,比如通过洋葱模型可以精确地控制响应的顺序~
浏览器的线程和进程
进程包括多个线程,一般浏览器有一个主进程和多个渲染进程,主进程就是负责管理用户界面,网络请求,渲染进程负责处理网页的渲染和交互
浏览器的线程用于执行不同的任务,主要的线程如下
GUI线程:负责渲染用户界面,处理用户交互事件,比如点击
渲染线程:负责解析html,css和js,将页面渲染成可视化的页面
js引擎线程:执行js代码
事件触发线程:用于管理事件队列
定时器线程:用于管理定时器线程,处理定时器回调
追问:js引擎线程能否和htm渲染线程同时进行
答:不能,js执行会阻塞html的渲染,因为js能操作dom,若能同时进行,就会造成不安全的渲染
引入第三方库一般有什么方式
- cdn引入,也就是用script标签的src
- 通过npm安装
- 本地文件引入,下载到本地然后script的src引入
- 模块化引入,import, from
追问:script阻塞可以用defer解决,加了defer还有什么影响
加了defer后,除了解决script的阻塞问题,还会让script异步加载,如果有多个defer的script,按照从上到下的顺序执行,遵循的宏任务队列;defer属性会让script延迟执行,直到dom构建完执行,因为defer的script会让DOMContentLoaded事件触发前执行;另外就是IE9极其以下版本不兼容
css的伪类
-
hover:鼠标悬停在元素上的状态
css
复制代码
a:hover { color: red; }
-
focus:被选中时的状态
css
复制代码
input:focus { border-color: blue; }
-
active:鼠标点击不放时的状态
css
复制代码
button:active { background-color: yellow; }
-
visited:选择已经被访问过的链接的状态
css
复制代码
a:visited { color: purple; }
-
first-child:某个子元素的第一个子元素
css
复制代码
li:first-child { font-weight: bold; }
-
last-child:某个子元素的最后一个子元素
css
复制代码
li:last-child { color: green; }
-
nth-child:某个子元素的指定位置的元素
css
复制代码
li:nth-child(odd) { background-color: #f2f2f2; }
-
nth-of-type:某个子元素的指定类型的子元素
css
复制代码
p:nth-of-type(2) { color: blue; }
es6新增的数据类型
Symbol
:表示唯一值,一般用作对象的key,确保属性的唯一性,像是set的迭代属性就放在symbol中,symbol值一般在控制台不会显示描述符
BigInt
:可以表示任意精度的值,不受Number的64位双精度浮点数范围的限制,在数字后面加一个n就可以表示为大整型
Promise和async,await的区别
追问:await报错后面是否还会执行
答:不会
继续追问:如果想要继续执行,怎么做
我回答的是try,finally,或者一个try,catch
js有哪些监听事件的方式
-
addEventListener
javascript
复制代码
document.getElementById('myButton').addEventListener('click', function() { console.log('Button clicked!'); });
-
on事件属性
javascript
复制代码
document.getElementById('myButton').onclick = function() { console.log('Button clicked!'); };
-
html事件属性
css
复制代码
<button onclick="console.log('Button clicked!')">Click me</button>
-
事件委托
javascript
复制代码
document.getElementById('parentElement').addEventListener('click', function(event) { if (event.target.tagName === 'BUTTON') { console.log('Button clicked!'); } });
-
jQuery事件
javascript
复制代码
$('#myButton').on('click', function() { console.log('Button clicked!'); });
vue2,vue3的区别
- 性能优化。vue3在VDom上有很多改进
- Composition API。贴近原生js的函数式写法
- 支持ts。vue3对ts的支持更加完善
- 响应式。Proxy代替了
Object.defineProperty
,提高了性能 - Tree-shaking支持。vue3更好地支持了Tree-shaking,打包后代码更加精简
- 更小的体积。
子组件如何监听父组件传值的变化
子组件可以通过watch来监听props的变化
computed,watch的区别
二者都是用于监听数据的变化,但是computed有缓存属性,watch在用法上更灵活,适用于监听特定数据走一个回调,处理异步
vue初始化页面有了解它底层的渲染过程吗
先通过new Vue()来创建一个vue实例对象,然后会将数据进行响应式处理,这样数据发生变化时,相关的视图就会自动更新,之后vue会将模板template解析生成VDom,然后将VDom进行挂载渲染到页面上,最后数据发生变化时,diff算法会对比新旧dom,只更新变化的VDom到真实Dom,这样保证了页面的高效更新
最后介绍公司业务
E公司
这个面试官挺好的,句句有回应,就是说话有丢丢结巴
自我介绍~
vue3响应式原理
追问:数据代理为什么比数据拦截好
答(这是面试官说的):数据拦截就是vue2的defineProperty
,Proxy性能会更好,可以对象嵌套对象,数据拦截只会代理第一层,是懒代理,defineProperty
会把对象进行一个深层次的递归,性能欠缺,proxy只需要for循环第一层,后面的对象在你使用的时候才会执行代理,因此vue3有个缺点就是,当你对一个对象添加属性时,vue不会自动响应这个变化,这就是对象新增属性不响应
的问题,可以用$set
解决这个问题
watch,watchEffect的区别
二者都是用于监听数据变化,watch接收三个参数,监听的数据,回调和一些参数,而watchEffect包含了watch的功能,无论是否监听响应式数据,watchEffect都会在初次进入页面时或者更新页面时立即执行一次,并且里面可以写调度函数,不会二次执行相冲突
说说Pinia
然后聊到了ts,面试官说ts不仅仅是给数据类型加了个限制,还有就是多人协作时的一个规范性,很多es6的高级语法是ts才具备的
你对于组件的想法
组件就相当于一个模块化的思想,设计好一个组件可以拿去重用,提高代码的复用性
组件传参如何双向绑定
我先说了父子组件是不建议去双向流动数据的,面试官说有时候需要这么干,还是在emit里面,写个语法糖updata-,这样props变量就看也i支持在外面v-model双向绑定
display:table设置为1列时,占多少分之一
没答上来,面试官说默认情况屏幕被划分为24块,也即是1/24
请求方法get,post区别
这里忘记了,全程都是面试官在解释
请求方法都是前后端一起规范好的,方法中delete就不说了,就是作删除用得,一般用户操作就是一个增删改查,增得话就是用post请求,查一般就是get请求,并且get请求是没有请求体body的,就相当于所有的参数都放在url中,所以不安全,并且url的长度是限制的。post请求是有body的,比如用户填一个form表单就是用post放到body中
因此就是get通过url传参,有长度限制,并且不安全,post请求有请求体,长度没有限制
后面聊了聊说现在写vue,一般都是用ts写的,而非template,并且他们公司是用低代码平台搭建前端应用,低代码可以更好地解决路由和菜单的管理,前后端配合
F公司
自我介绍+项目~
还问我前端学了多久……
组件通讯
父子:父组件v-bind绑定属性用于传值,子组件props接收
子父:父组件订阅一个事件,子组件通过$emit发布该事件,且携带事件参数,让父组件订阅生效
vuex,pinia
vue组件通信【父子,子父,vuex】 - 掘金 (juejin.cn)
eventbus
eventbus就是用于vue组件通讯的模式,它是一个全局总线,可以用来在不同的组件之间进行传递信息和触发事件,不需要明确地通过父子组件传递props或者走回调的形式来实现
先创建一个vue实例对象,用它来触发和监听事件,一般这个写在入口文件或者根组件,让后将其挂载到vue的原型上,这样所有的组件都可以访问到它
比如下面的组件A和组件B借助eventbus进行通讯,A组件点击按钮发送信息,B组件监听到该消息
javascript
复制代码
// EventBus.js import Vue from 'vue'; // 创建一个空的Vue实例作为事件总线 const EventBus = new Vue(); export default EventBus;
xml
复制代码
// ComponentA.vue <template> <button @click="sendMessage">Send Message</button> </template> <script> import EventBus from './EventBus'; export default { methods: { sendMessage() { // 发送名为 'message' 的事件,附带一些数据 EventBus.$emit('message', 'Hello from Component A'); } } } </script>
xml
复制代码
// ComponentB.vue <template> <div>{{ receivedMessage }}</div> </template> <script> import EventBus from './EventBus'; export default { data() { return { receivedMessage: '' }; }, created() { // 监听名为 'message' 的事件 EventBus.$on('message', message => { this.receivedMessage = message; }); } } </script>
通过使用eventbus就不需要了解组件的层级关系,当然也不能滥用,过多的全局事件会导致代码难以维护
抛开vue,如何用js实现组件通信
- 定义全局变量:所有组件都可以直接访问和修改这些数据
- 发布-订阅模式:自定义事件,组件可以订阅某个事件,事件被另一个组件发布时,订阅者收到通知并执行相关操作
- 回调函数:一个组件将自己的函数传给另一个组件,在适当的时候调用这个函数
vue源码看过吗,说下
只看过响应式和路由……
输入url到页面渲染的整个过程
自行吟唱~
dns缓存在哪里
dns(Domain Name System)缓存通常存在于操作系统和浏览器中
- 操作系统的dns:本地维护一个dns缓存,用于存储最近解析过的域名和对应的ip
- 浏览器的dns缓存:现代浏览器也会维护自己的dns缓存,同样存储解析过的域名和ip,这样可以避免重复的dns查询
如何解决js阻塞渲染
js阻塞渲染是因为js线程和渲染线程不能同时进行,可以用async和defer属性解决
async和defer的区别
二者都是可以异步加载script标签,但是defer最后是有一个执行顺序的,这个顺序就是代码顺序,async执行顺序不确定,取决于哪个脚本先加载完成
因此脚本之间互相独立并且顺序不重要时可以使用async属性,若有依赖关系则使用defer属性
设计模式有了解多少
单例模式:确保一个类只有一个实例对象,并提供一个全局访问点
工厂模式:将对象的创建过程封装在一个工厂方法中,根据不同的条件创建不同类型的对象
观察者模式:定义对象之间一对多的依赖关系,一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新
发布订阅模式:至今不明白和观察者模式什么区别,发布者可以有多个订阅者,它发布信息并通知所有的订阅者,订阅者收到信息可以去执行相应操作
闭包
因提到了GC,有了后面的问题……
垃圾回收机制你了解吗
垃圾回收机制Garbage Collection 简称GC,是一种自动内存管理的技术,在程序运行中自动回收不再使用的内存,也就是管理内存的分配和释放
js的GC主要有两种:
- 标记清除:这是最常见的策略,GC会周期性的扫描程序中的对象,标记那些仍然被引用的对象,GC会清楚那些没有被标记的对象,然后释放它
- 引用计数:实际上很少用这个,GC会根据每个对象的引用计数,对象被创建时,计数为1,被引用时,计数加1,不在被引用时,计数减1,计数为0时,释放它
异步你了解吗
event-loop
先同步,后执行微任务,再执行宏任务,宏任务和微任务都有相应的队列执行,执行一次宏任务之前掏空前面的微任务队列~
用户打开首页,加载5s才看到了内容,优化方案都可以说说
这么久才看到页面有可能是因为数据资源大,用户网速慢,服务器响应慢
优化如下:
- 对css,js和图片等静态资源进行压缩处理,减小文件大小,加快下载速度;
- 将页面的非关键资源设置成延迟加载,使页面首页加载时只加载必要的内容,后再加载其他资源;
- 不影响页面渲染的资源可以使用异步的方式进行加载;
- 将静态资源部署到CDN上,利用cdn的分布式节点加速资源的传输
- 利用浏览器缓存机制和服务端缓存机制,减少重复请求
- 对前端代码进行优化,减少重复逻辑
大文件上传
你项目跨域是怎么解决的
跨域就是因为浏览器的同源策略,后期单独出篇文章来讲,我答的是cors,还有josnp
简单请求和非简单请求
简单请求是浏览器向服务器发送的一种特定类型的跨域请求,满足如下条件就不会触发浏览器的预检请求
- 使用以下方法:get,head,post
- 请求头只包含以下字段:accept,accept-language,content-language,content-type(有限制)
满足这些条件浏览器会将其视为简单请求,直接发送给后端,不会触发预检请求,服务器收到请求后,若允许跨域,则会返回响应
不满足那些条件就是非简单请求,这些请求会触发浏览器的预检请求,服务器接收到预检请求后,需要返回相应的cors头部信息来确认是否允许跨域
强缓存和协商缓存了解吗
强缓存和协商缓存是浏览器在缓存资源时使用的两种不同策略
强缓存:强缓存是通过设置http响应头的cache-control和expires字段来实现的,当浏览器发送请求时,会先检查缓存中是否存在资源以及是否过期,若没有则直接从缓存中获取资源,不会向服务器发送请求。
协商缓存:协商缓存是通过http响应头中的etag和last-modified字段来实现的,当浏览器发送请求时,会先向服务器发送一个验证请求,询问资源是否有更新,服务器收到验证请求后,会根据资源的内容来生成一个唯一标识etag和最后修改时间last-modified,若资源没有发生变化,则服务器返回304状态码,告诉浏览器可以继续使用缓存中的资源,若资源发生了变化,则服务器返回新的资源内容和相应的状态码
强缓存和协商缓存可以结合使用,浏览器在接收到服务器的响应时会根据cache-control和expires字段判断是否使用强缓存,如果强缓存失效,则会发送一个带有if-none-match或if-modified-since字段的请求,进行协商缓存验证。
keep-alive源码看过吗,描述下
先创建一个缓存对象,核心逻辑是获取第一个子组件的VNode,然后获取组件的唯一key,如果缓存中存在该组件实例,那么直接返回缓存中的实例,若没有则创建一个实例并存入缓存中,最终还要通过mixin来监听组件的销毁事件,在组件销毁时从缓存中移除
mixin
mixin是一种在vue中用于复用组件选项的方式。通过mixin,可以将一组组件选项合并到多个组件中,mixin通常是一个js对象,可以包含任意组件选项,比如data,methods,computed等,当一个组件使用mixin时,mixin中的选项会被合并到组件的选项中
前后端通讯
- http请求
- ajax,js异步与服务器进行通信
- websocket,允许前端和后端建立持久连接,并进行双向实时通信,比如在线聊天
- SSE(Server-Sent Events),允许服务器向客户端推送实时更新的数据,与websocket不同,sse只能从服务器向客户端发送数据,不能双向通信
axios
axios基于Promise,让我们可以轻松地发送异步请求,基于XML和Fetch,并且使用promise对http请求进行封装,还可以进行拦截操作,可以在请求或响应在发送或者接收前进行拦截和处理,比如弹出框可以借助它来实现,另外还可以取消请求,避免不必要的资源浪费,另外axios提供了丰富的错误捕获机制,可以自定义全局的错误处理函数
返回一个数字的千分位
比如数字123返回字符串123,数字1234返回字符串1.234,数字123456返回字符串123.456……
先将数字转字符串,然后3个字符串一起作为数组的元素,最后数组join时带个点
ini
复制代码
let n = 1234 // 输出"1.234" function getThousandSign (n) { const str = n.toString() const arr = [] let len = str.length for(let i = len; i > 0; i -= 3) { let block = str.substring(i - 3, i) arr.unshift(block) } return arr.join('.') } console.log(getThousandSign(n)); // 1.234
G公司
这家公司是做uniapp开发的
uniapp如何实现下拉刷新,上拉加载
下拉刷新:使用页面钩子onPullDownRefresh处理逻辑,页面中使用refresh-view组件展示下拉刷新的效果,并监听refresh事件
上拉加载:使用页面钩子onReachBottom处理逻辑,页面中使用scroll-view组件,并监听scrolltolower事件
如何实现多端适配
通过# ifndef 来包裹顶部电量信息view盒子
vue和nvue
vue.js:vue时uniapp中主要的开发方式,适用于多个平台的开发
nvue.js:nvue时uniapp中的一种新的开发方式,专门为小程序端而设计的一种开发方式,通过使用原生组件和原生渲染方式来提高小程序端的性能和体验
封装过组件吗
定位的缺点
position用absolute,fixed会导致元素脱离文档流,并且二者依靠最近的祖先元素发生变更会导致定位不准
后面一直在闲聊……
H公司
这个面试官一直拿着我的往期文章来问
自我介绍+项目
深浅拷贝
面试官:手写一个浅拷贝和一个深拷贝(拷贝详解) - 掘金 (juejin.cn)
自己写的文章当然有印象,不过关于深拷贝我没处理函数,因此他接着问我如何深拷贝函数
函数得话应该就是直接返回即可,但是如果是箭头函数,那么就不能有实例对象,因此可能需要用上eval()生成一个新函数
类型判断
深入认识js四大常用数据类型判断,一次性带你搞明白(内含面试热点)! - 掘金 (juejin.cn)
闭包
面试官:聊聊js闭包。来看这篇,小白也能读懂!(内含调用栈及作用域链的详细讲解) - 掘金 (juejin.cn)
手写防抖节流
面试官:手写下防抖节流 - 掘金 (juejin.cn)
localStorage,cookie,session的区别
js事件触发
面试官:请问js事件触发过程是怎样的 - 掘金 (juejin.cn)
为什么0.1 + 0.2 !== 0.3
因为浮点数精度问题,这些数被转换成二进制时,二进制是无法精确表示一些十进制小数,0.1和0.2在二进制中是无限循环小数,会产生精度丢失
追问:如何解决
将浮点数乘以10,使其最终转换成整数再进行比较
es6新特性
call,apply,bind区别
三者都是去显示改变this指向,call和apply的区别是apply可以以数组的形式进行传参,bind会返回一个新的函数,需要再次进行调用
new操作的过程
在构造函数中创建一个this对象,然后构造函数中的内容就相当于往this里面挂属性,另外还会放一个实例对象的隐式原型,也就是构造函数的显示原型,最终return出这个this对象
js中this究竟指向哪里?现在终于搞定了! - 掘金 (juejin.cn)
css垂直水平居中
元素隐藏
最新css面试题汇总【助力金三银四】 - 掘金 (juejin.cn)
减少重排重绘
输入url到页面渲染后半段:回流,重绘,优化【一次性带你搞明白】 - 掘金 (juejin.cn)
这个时候我就笑着说面试官拿着我的文章来问,面试官说这些八股其实在开发中确确实实是会用上的
谈谈你对vue的认识
mvvm,响应式,组件化,生态……
vue的插槽
-
默认插槽,子组件未命名的插槽,父组件传递内容到子组件时,子组件通过一个不带属性的slot标签来定义默认插槽的位置
xml
复制代码
<!-- 子组件 --> <template> <div> <slot></slot> </div> </template> <!-- 父组件 --> <template> <my-component> <div>默认插槽内容</div> </my-component> </template>
-
具名插槽,允许父组件向子组件传递特定名称的内容,并指定插入到子组件的特定位置,子组件通过slot标签的name属性来定义具名插槽的位置
xml
复制代码
<!-- 子组件 --> <template> <div> <slot name="header"></slot> <div>子组件内容</div> <slot name="footer"></slot> </div> </template> <!-- 父组件 --> <template> <my-component> <template v-slot:header> <h1>头部内容</h1> </template> <template v-slot:footer> <p>底部内容</p> </template> </my-component> </template>
-
作用域插槽,允许子组件将数据传递给父组件,并在父组件中进行渲染,子组件通过slot标签中使用具名插槽的方式来传递数据,父组件通过slot指令来接收数据并进行渲染
xml
复制代码
<!-- 子组件 --> <template> <div> <slot name="item" v-for="item in items" :item="item"></slot> </div> </template> <!-- 父组件 --> <template> <my-component> <template v-slot:item="slotProps"> <div>{{ slotProps.item }}</div> </template> </my-component> </template>
nextTick
细聊vue的nextTick - 掘金 (juejin.cn)
前端路由
面试官:谈谈前端路由的实现原理【hash&history】 - 掘金 (juejin.cn)
map和weakmap的区别
Iterator-Set-Map-WeakSet-弱引用详解 - 掘金 (juejin.cn)
git切换分支用什么指令
csharp
复制代码
将修改的文件暂存起来 git add myfile.txt 保存变更到堆栈中 git stash 切换到其他分支进行工作 git checkout other-branch 在其他分支上完成工作后,可以恢复之前保存的变更 git stash apply
手写个ajax
详谈ajax发展历程 - 掘金 (juejin.cn)
vuex和pinia的区别
vuex基于vue2的OptionsAPI,pinia基于vue3的CompositionAPI,并且更兼容ts……
最后
另外有不懂之处欢迎在评论区留言,如果觉得文章对你学习有所帮助,还请”点赞+评论+收藏“一键三连,感谢支持!!!