前端中高级面试题

1.大屏的自适应问题

         

目的使项目内容根据屏幕尺寸变化,并且居中对齐

// 1.监听屏幕的尺寸获得和原先的尺寸比例

// 2.获得左侧和右侧的距离

// 3.通过transform中的translate和scale进行变化

export function autoScale(selector, options) {
    const el = document.querySelector(selector)
    const { width, height } = options
    el.style.transformOrigin = 'top left'
    el.style.transition = 'transform0.5s'
    function init() {
        const scaleX = innerwidth / width
        const scaleY = innerHeight / height
        const scale = Math.min(scaleX, scaleY)
        const left = (innerwidth - width * scale) / 2
        const top = (innerHeight - height * scale) / 2
        el.style.transform = ` translate(${left}px, ${top}px)scale(${scale})`
    }
}

2.如何实现token无感刷新

思路:

简单说就是当短token失效时利用长token去获取短token实现无感刷新的效果

1.在响应拦截器中监听响应码401时调用长token接口获得短token并储存本地中

2.重新调用原接口

要注意的细节点:

1.当 refresh token 也过期的这种情况,会造成死循环,所以可以在请求头中引入一个变量标志进而判断是否是refresh token过期还是 access token过期

2.当refresh token请求失败时,需要走重新登录的逻辑

3.并发刷新 token的情况,多个请求并发且accesstoken刚好失效,这时会造成冗余发送请求,解决方法是实例化一个全局变量的promise,如果其他的请求进来就返回这个promise,最后利用promise上的finally将promise赋值null

3.js的事件循环机制(EventLoop)

学习地址https://blog.csdn.net/snowball_li/article/details/125236024

         JavaScript 是单线程语言,这意味着它在同一时间只能执行一个任务。为了实现异步操作,JavaScript 使用了事件循环机制。        

        js事件循环机制是指js在处理各种事件(例如用户交互、网络请求、定时器等)时,如何协调执行这些事件的机制。JavaScript 事件循环机制分为JS执行栈和任务队列两部分。

        JS调用栈是一种后进先出的数据结构,当函数被调用时,会被添加到栈中的顶部,执行完成之后就从栈顶部移出该函数,直到栈内被清空。任务队列是先进先出的数据结构,当主线程空闲时,就会去任务队列中按照顺序读取一个任务放入到栈中执行。

        

在JavaScript事件循环机制中,任务分为宏任务和微任务。
宏任务包括setTimeout、setInterval、setInterval、NodeJs读取文件I/O操作等;
微任务包括Promise的thencatchfinally回调、MutationObserver、Node 中process.nextTick等。
在每次事件循环开始时,JavaScript会先执行所有的微任务队列中的任务,然后再执行宏任务队列中的任务(promise是同步任务)

        事件循环机制是指:

1、代码执行时,先执行同步任务,然后将异步任务放入任务队列中,等待执行。
2、当所有同步任务执行完毕后,JavaScript引擎会去读取任务队列中的任务。
3、将队列中的第一个微任务压入执行栈中执行,所有微任务执行完毕后将其出栈如果产生宏任务则放入宏任务队列中。

4、执行宏任务
5、如此循环执行,直到任务队列中的所有任务都执行完毕。

        这就是JavaScript实现异步的基本原理,通过将异步任务放到任务队列中,并通过事件循环机制来实现异步执行。

console.log('start')
 
setTimeout(() => {
  console.log('timeout1')
  Promise.resolve().then(() => console.log('then2'))
}, 0)
 
new Promise((resolve) => {
  console.log('promise1')
  resolve()
}).then(() => {
  console.log('then1')
  setTimeout(() => {
    console.log('timeout2')
  }, 0)
})
 
console.log('end')
 
答案:start, promise1, end, then1, timeout1, then2, timeout2
 
解析:同样的,Promise对象和.then()方法是同步执行的,但是回调函数中包含的Promise对象和.then()方法时异步执行的,会被放到任务队列中等待执行。因此start, promise1, end, then1会先输出。然后在任务队列中执行setTimeout中的回调函数,输出timeout1,然后将包含的Promise对象和.then()方法放到任务队列中。在任务队列中执行.then()方法,输出then2。最后在任务队列中执行第二个setTimeout中的回调函数,输出timeout2。

4.vue中$nextTick的原理

        定义:在下次 DOM 更新循环结束之后执行延迟回调。

        原理:当数据在发现变化的时候,vue 并不会立刻去更新 Dom 。而是将修改数据的操作放在一个异步操作队列中。如果我们一直修改相同数据,异步操作队列还会进行去重。等待同一 事件循环 中的所有数据变化完成之后,会将队列中的事件拿来进行处理,进行DOM的更新。

5.vue2中的data为什么要是个函数

        vue中的data写成函数是为了确保每个组件实例都拥有独立的数据副本,避免数据共享和相互影响的问题。

在Vue中,组件是设计为可复用的单元,这意味着它们可能会被多次使用。如果data直接被定义为一个对象,那么所有的组件实例将会共享同一个data对象。这样,当某个实例修改了data中的数据时,其他所有实例中的数据也会受到影响,导致不可预测的行为和bug。

为了解决这个问题,Vue的设计者们将data选项设计为函数。当组件被创建时,Vue会调用这个函数,并返回一个新的数据对象。这样,每个组件实例都会拥有自己独立的数据副本,互不干扰。具体来说,当Vue创建组件实例时,它会在初始化过程中调用data函数,并将返回的对象作为组件实例的data属性。这样,在组件中可以通过this.datathis.$data来访问和修改这些数据。

使用函数形式的data选项还有其他好处。例如,函数内部可以进行一些额外的逻辑处理,比如计算属性、方法、监听器等,使得数据管理更加灵活和可扩展。此外,函数形式的data选项还可以接收组件的props作为参数,从而实现更高级的数据初始化逻辑。

总之,将data选项定义为一个函数是为了保证每个Vue组件实例都拥有独立的数据副本,避免数据共享和相互影响的问题,并且提供了更多灵活性和扩展性。

6.前端如何处理跨域问题

一、什么是跨域

跨域也称为非同源策略请求,就是去非同源地址获取数据的行为
只要页面,向非同源地址,发出了ajax / fetch请求,此时就出现了跨域问题。

专业的解释是,两个不同源的服务去访问对方的资源,就是所谓的跨域,而浏览器处于安全方面的考虑是不允许跨域请求的

二、什么是同源

同源是指协议、域名、端口都相同,其中有一个不同就是非同源

解决办法

1.通过jsonp实现跨域

缺点:1.只能发送get请求

优点:支持老的IE浏览器、适合加载不同域名的js、css,img等静态资源

2. 跨域资源共享(CORS)

1.普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置
2.若要带cookie请求:前后端都需要设置。(而且一定要把接口写成域名形式的,不然cookie还是带不上的  测试的的时候我改了hosts文件)

两种请求
一种是简单请求(get,post)
另一种是非简单请求(put,delete) (这个会请求两次)

非简单请求
会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求。
"预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的
服务器收到"预检"请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应

3.nginx代理跨域

都是搭建一个服务器,直接在服务器端请求HTTP接口,这适合前后端分离的前端项目调后端接口

4.postMessage跨域

        postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:
a.) 页面和其打开的新窗口的数据传递
b.) 多窗口之间消息传递
c.) 页面与嵌套的iframe消息传递
d.) 上面三个场景的跨域数据传递

        用法:postMessage(data,origin)方法接受两个参数
data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
origin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。

5.WebSocket协议跨域
6.nodejs中间件代理跨域

node中间件实现跨域代理,原理大致与nginx相同,都是通过启一个代理服务器,实现数据的转发。

7. window.name + iframe跨域

window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在

8.location.hash + iframe 跨域

9.document.domain+iframe

适合主域名相同,子域名不同的跨域请求

7.浏览器的回流与重绘

参考地址https://blog.csdn.net/snowball_li/article/details/123280534

一、从上面这个图上,我们可以看到,浏览器渲染过程如下


1、解析HTML,生成DOM树,解析CSS,生成CSSOM树
2、将DOM树和CSSOM树结合,生成渲染树(Render Tree)
3、Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置、大小)
4、Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素
5、Display:将像素发送给GPU,展示在页面上。

二、什么是回流重绘

回流:当render tree中元素因为布局或者几何属性发生变化需要重新构建时,这个过程称之为回流。

重绘:当render tree中元素不因为布局或者几何属性发生变化仅仅只是外观样式发生变化需要更新元素,这个过程称之为重绘。

三、重绘与回流的区别

回流必将引起重绘,而重绘不一定会引起回流。
比如:只有颜色改变的时候就只会发生重绘而不会引起回流
当页面布局和几何属性改变时就需要回流。
比如:添加或者删除可见的DOM元素,元素位置改变,元素尺寸改变——边距、填充、边框、宽度和高度,内容改变。

四、会触发重绘或回流/重排的操作


1、添加、删除元素(回流+重绘)

2、隐藏元素,display:none(回流+重绘),visibility:hidden(只重绘,不回流)

3、移动元素,如改变top、left或移动元素到另外1个父元素中(重绘+回流)

4、改变浏览器大小(回流+重绘)

5、改变浏览器的字体大小(回流+重绘)

8.前端性能优化

前端性能着重考虑的两方面

1.首屏时间、和白屏时间

2.操作速度以及渲染速度

优化方式:

a.异步加载,适合体积比较大,又不是马上需要的功能,比如图片压缩功能的第三方库,只有在图片上传的时候才会用到

b.将库的版本更新,因为有些老的库不支持打包工具的tree-shaking,只把用了的方法打包进去,打包体积会减小

c.能不用第三方库就不用第三方库,自己写体积最小

d.骨架屏、loadiing遮罩等操作

e.页面数据比较多的话可以分批滚动渲染

f.减少操作dom

多用v-show少用v-if、循环的时候加好key值、子组件需要的时候可以用keep-alive缓存

前端中高级开发面试题通常会涉及更深层次的技术知识和实践经验。下面是一些常见的主题以及它们的具体问题示例: ### 一、HTML/CSS 深度理解 1. **BFC是什么?它有哪些特性及应用场景** - BFC (Block Formatting Context) 是一种独立的渲染区域,在这个区域内元素按照一定的规则布局,并且不会影响到外部的其他内容。 特点包括: * 内部盒子会在垂直方向上一个接一个地排列; * 它里面的内容绝对不会超出容器边缘;可以防止浮动元素覆盖非浮动元素的情况发生等。 2. **Flexbox 和 Grid 的区别在哪?什么时候应该选择哪一个?** Flexbox主要用于一维设计(即行内或者列),而Grid更适合处理二维布局(行列同时存在)。如果需要创建复杂的网格系统,则建议采用CSS Grid。 3. **如何解决页面加载性能优化的问题?** 可以通过减少HTTP请求次数,合并文件资源,压缩图片大小等方式提高网页打开速度。此外还可以利用浏览器缓存机制保存静态资源如样式表、脚本库等,避免每次访问都重新下载整个网站的所有组件。 ### 二、JavaScript 高级技巧 4. **解释闭包的概念并给出实际例子说明其作用** 闭包是指函数与其词法环境之间形成的一个组合体,即使该函数在其原始范围内已经执行完毕也可以继续引用其中变量值的一种现象。例如: ```javascript function createCounter() { let count = 0; return function(){ console.log(++count); } } const counterA = createCounter(); counterA(); // 输出 "1" ``` 5. **谈谈this指向原则及其变化规律** this关键字取决于调用上下文而非定义位置。普通函数默认绑定全局对象window(严格模式下未指定则为undefined),作为方法时属于当前实例对象;箭头函数内部this永远等于外层最近一层函数的作用域里的this... 6. **事件委托的工作原理是什么样的呢?** 利用了冒泡阶段的特点将所有子孙节点触发的目标事件统一交由某个祖先级别监听器负责捕获响应。比如对于动态生成列表项来说,只需给ul加一次click监听即可对li标签操作作出反应,无需针对每一条记录单独设置处理器,极大提高了程序效率减少了内存占用量。 7. **Promise链式调用过程解析** 当resolve/reject回调被执行之后就会返回一个新的promise状态承诺对象供下一个then/catch消费,从而实现了异步任务之间的顺序衔接。并且每个链接环节都可以传递结果数据向下流转直到完成最终的操作流程。 8. **async/await语法糖背后隐藏着哪些特点?** async修饰符标识此函数体内含有异步等待表达式 await ,当遇到后者暂停代码后续指令执行直至右侧promise resolve 结果到来才恢复运行。二者搭配使得基于 promise 编写的代码看起来像同步那样简洁明了,易于理解和维护调试错误信息追踪定位更加方便快捷。 9. **深拷贝浅拷贝的区别在哪里?** 浅复制只是把目标对象第一层次属性直接赋值过去,但如果包含有复杂的数据结构的话原地址还是保持不变;相反深度克隆则是递归遍历每一个成员项彻底重建出一份全新的副本出来不再互相干扰依赖关系。 ### 三、框架与工具链 10. **Vue生命周期钩子函数都有哪些重要场景应用?** Vue提供了一系列内置生命周周期挂钩让开发者可以在特定的时间点插入自定义逻辑来进行初始化配置、更新视图或者其他必要的交互动作。典型案例如created用于获取初始数据,mounted适合挂载完成后启动定时器轮询接口请求之类的功能需求。 11. **React JSX本质意义及其优势体现于何处?** JSX是一种类似于XML标记语言风格扩展形式允许我们在jsx模板里混合书写html样式的DOM树形结构的同时支持嵌入js运算表达式来增强灵活性。相比于传统的模版引擎,这种方案能够更好地结合react虚拟dom的优势,简化组件构建步骤并提升整体渲染效能。 12. **Webpack打包过程中常用插件推荐几个?** HTMLWebpackPlugin 自动生成index.html入口文件并将所有的bundle js/css自动引入; CleanWebpackPlugin 清理旧版本产出目录下的无用冗余资源; MiniCssExtractPlugin 分离css样式成单独文件而不是注入style 标签之内等等都是很实用高效的辅助类库可以帮助我们高效便捷地管理项目工程化建设工作流。 --- 当然这只是冰山一角,具体考察重点还要看岗位职责范围和个人专业背景经历的不同侧重点有所差异。希望以上能为你带来一些参考价值!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值