整理前端面试中遇到的问题-持续更新

一.Html + Css + Js篇

1.请说出LocalStorage、SessionStorage、Cookie、Session的区别

SessionStorageCookieSession
类型客户端存储客户端存储Http协议服务端存储
生命周期持久化存储临时存储,关闭浏览器后清除可以设置过期时间,也可以设置关闭浏览器后清除依赖服务器配置,通常会话结束后消失
容量约5M约5M约4kb取决于服务器
作用域同源策略限制同源策略限制通过路径和域名设置作用域服务器唯一ID
交互不主动携带不主动携带每次HTTP请求都会自动发送到服务器,服务器也可以设置或修改通过session ID(通常存储在cookie中)关联客户端和服务器端的会话状态
用途适合存储不敏感的用户偏好设置、主题选择等长期客户端数据适用于存储会话相关的临时数据,如表单输入信息主要用于认证、会话管理、用户跟踪等,以及一些小型的个性化设置存储用户登录状态、购物车信息等需要在多个请求间保持的状态数据
存储格式键值对键值对字符串不固定

        总之,LocalStorage和SessionStorage都属于客户端管理,Cookie和Session属于服务端和客户端之间的交互。

2.width:auto 和 width:100%的区别

  • width: auto: 当设置为 auto,浏览器会自动计算元素的宽度。
    对于非定位元素(static定位),宽度会根据元素的内容、内边距(padding)、边框(border)以及所在包含块的宽度进行自动调整,以适应内容的大小。这意味着如果内容增多,宽度会随之增大(在没有固定宽度约束的情况下),同时考虑其他影响宽度的样式,如 min-width, max-width 等。自动宽度允许元素适应其内容,而不是填满其父元素。
  • width: 100%: 设置为 100% 意味着元素的宽度将占据其父元素内容区域的整个宽度。
    这个值不包括父元素的内边距、边框或是外边距,纯粹基于父元素的宽度计算得出。如果父元素的宽度变化,子元素的宽度也会相应地调整。
    如果子元素有额外的内边距、边框,这些不会被计算在 100% 内,可能导致总占用空间超过父元素宽度,这时候可能会出现滚动条或者溢出情况
    如果父元素没有明确的宽度(例如也是 auto 或未设定),100% 可能无法按预期工作,因为它是相对于父元素的实际宽度计算的。

        可以根据这张图可以直观的感受区别:

3.请说明img 的 srcset 属性的作用 

    srcset 是 HTML <img> 标签中的一个属性,用于提供图片源集,使得浏览器可以根据设备的屏幕分辨率、视口尺寸或者像素密度等条件来选择最合适的图像资源进行加载。这一特性有助于实现响应式图像,提升网页性能和用户体验。如:

<img src="./imgs/banner_img1_03.png" srcset="./imgs/banner_img1_03.png 480w, ./imgs/react.webp 768w, ./imgs/vue.jpg 1024w"/>

在上述例子中,src 属性提供了默认的图片资源,用于不支持 srcset 的浏览器。第一张图片后面跟着的480w代表着表示小图适用于最大宽度480像素的设备,480w 指的是图片的宽度为480像素宽。

4.简要说明1rem、1em、1vh、1px各自代表的含义

  • 1px:代表1个像素单位大小。
  • 1em:代表当前元素字体fontSize的单位大小。默认情况下等于其父元素的字体大小。这意味着em值会随着父元素字体大小的变化而等比例缩放
  • 1rem:rem是相对于根元素的fontSize的大小。不随嵌套层次变化,提供了一个统一的、基于文档的缩放基准。
  • 1vh:视口高度的百分比,1vh等于视口高度的1%。随着浏览器窗口高度的变化,vh单位会相应调整,常用于实现响应式布局,尤其适合于依据可视窗口大小调整元素尺寸的情况。

5.style 标签写在 body 后与 body 前有什么区别?

        按照 HTML 标准,<style> 标签应当放置在 head 中或者特定条件下而非 body 中。尽管现代浏览器对这种非标准用法较为宽容,但这仍违反了规范。

  • 写在Body前面:浏览器在遇到 CSS 样式定义时会先加载并解析这些样式规则,然后在后续遇到 HTML 结构时应用相应的样式进行渲染。这样可以在元素首次渲染时就应用样式,避免了无样式内容的闪烁。
  • 写在Body后面:浏览器会先解析 HTML 结构,当遇到位于 body 结尾的 <style> 标签时,它必须停止当前的渲染过程,回头去应用新发现的样式规则。对于用户而言,这可能导致页面内容先以无样式或默认样式显示,之后突然改变外观,影响用户体验。特别是对于大型页面,这种做法会显著增加页面完全渲染完成的时间。

6.常见的响应式布局分别有哪些?在实际项目中如何选择?

  • Flex布局:易于创建响应式界面,能够自动调整项目大小以填充容器,对齐和分配空间非常灵活。但对于某些特定的布局模式(如等分布局),在极端尺寸下可能需要额外的调整。
  • Grid布局:提供了一种二维布局系统,非常适合创建复杂的网页布局,能够精确控制网格的行和列。但在老旧的浏览器中支持度有限,可能需要回退方案。
  • 媒体查询:允许根据设备视口尺寸、屏幕定向等条件应用不同的CSS样式,非常灵活。但需要手动设定断点,维护成本较高,且可能产生大量重复或冗余的CSS代码。
  • Bootstrap等响应式框架:提供预设的类和组件,快速实现响应式设计,减少开发时间。但可能引入不必要的CSS和JavaScript,影响页面加载速度,且定制化程度受限。
  • 百分比布局:元素大小随容器变化,适用于简单的流式布局。但难以处理复杂的布局需求,尤其是需要精确控制元素位置和大小时。
  • 子绝父相布局:结合相对定位的父元素和绝对定位的子元素,可以实现灵活的布局效果。但代码复杂,特别是在需要响应式调整时,可能需要大量媒体查询或JavaScript辅助。

        在实际应用中,要根据项目特点、浏览器兼容性、开发效率、性能以及可维护性进行考虑。例如在复杂的网格布局项目中要考虑到Grid布局,但是还要综合考虑浏览器兼容性,进行评估。

7.响应式布局与自适应布局的区别是什么?

响应式布局自适应布局
核心特点响应式布局侧重于使用 CSS 媒体查询 (@media 规则) 和灵活的网格系统来动态调整页面的布局结构和内容的展示方式。这意味着同一页面可以根据不同的屏幕尺寸呈现出完全不同的布局,比如列可能变成行,隐藏或显示某些内容,调整图片尺寸等自适应布局主要是预先设计好几种固定的布局模板,每个模板针对特定的屏幕尺寸或设备类型。当页面加载时,会根据检测到的设备屏幕尺寸选择最合适的布局模板。这种布局方式不会像响应式那样流畅地改变布局结构,而是“跳跃”到最匹配的布局状态。
使用场景适合内容丰富、结构复杂的网站,需要在多种设备上提供一致的用户体验,而不仅仅是调整内容的大小或简单堆叠适用于内容相对固定、布局变化不那么频繁的网站,或对特定设备有专门优化需求的场景
技术实现利用上述百分比单位、flexbox、grid布局以及媒体查询和Bootstrap来实现通常依赖于服务器端检测、CSS媒体查询或JavaScript来判断设备类型或屏幕尺寸,然后加载相应的CSS样式或HTML结构

8. 同步和异步的区别

同步异步
执行顺序同步代码按顺序执行,每个任务必须等待前一个任务完成后才能开始。这意味着程序的执行是线性的,后面的代码会阻塞等待前面的代码执行完毕。异步使得多个任务可以并发执行,不必等待一个任务完成后才开始下一个,这对于提升性能和用户体验至关重要,尤其是在处理I/O密集型操作时。
阻塞性质在执行同步操作时,整个线程会被阻塞,直到该操作完成。如果某个任务耗时较长(如I/O操作或网络请求),则会导致UI冻结,影响用户体验。异步代码允许程序在等待某个操作(如文件读取、网络请求)完成的同时继续执行其他任务,提高了程序的响应性和效率。
结果获取按顺序直接获取异步操作通常通过回调函数、Promise对象或async/await语法来管理。一旦异步操作完成,会通过回调或Promise的resolve/reject通知调用者,或在async函数中使用await等待结果。

9.script 标签中 defer 和 async 的区别

deferasync
执行顺序保证脚本按照它们出现在文档中的顺序执行不保证脚本在文档中的顺序执行
页面加载不阻塞页面加载不阻塞页面加载,但是由于async不等待文档解析完毕,所以可能更快执行
使用场景适用于那些不需要立即执行,且执行顺序重要的脚本,比如多个脚本之间有依赖关系。适用于那些不依赖于文档解析的脚本,且相互之间也没有依赖关系,比如第三方统计脚本或分析脚本。

10.简述防抖和节流的作用和区别 

  • 防抖:防抖技术确保一个函数在频繁触发时,只有在最后一次触发后的指定延迟时间过后才执行一次。如果在延迟期间又有新的触发,则重新开始计时。这有助于减少不必要的函数调用,比如在网络请求频繁变动的输入框中,仅在用户停止输入一段时间后再发送请求。
  • 节流:节流技术确保一个函数在频繁触发时,无论触发多么频繁,都保证在指定的时间间隔内只执行一次。这可以用来限制函数的执行频率,例如限制滚动事件的处理函数每秒只执行一次,保持动画流畅而不占用过多计算资源。

        总之,防抖就是在一定时间后执行操作,而节流是在一定时间内只执行一次,以下是代码示例:

防抖:

function debounce(func, wait) {
    let timeout;
    return function(...args) {
        clearTimeout(timeout);
        timeout = setTimeout(() => func.apply(this, args), wait);
    };
}

// 使用防抖函数
const handleInput = debounce(function(value) {
    console.log("查询输入:", value);
}, 300);

// 假设这是用户连续输入的模拟
inputElement.addEventListener('input', function(e) {
    handleInput(e.target.value);
});

节流:

function throttle(func, limit) {
    let inThrottle;
    return function(...args) {
        if (!inThrottle) {
            func.apply(this, args);
            inThrottle = true;
            setTimeout(() => (inThrottle = false), limit);
        }
    };
}

// 使用节流函数
const handleScroll = throttle(function() {
    console.log("滚动事件处理");
}, 200);

// 绑定滚动事件
window.addEventListener('scroll', handleScroll);

11.请简述call()、apply()、bind()之间的区别

  • call():接受的第一个参数表示this要指向的对象,其余参数表示调用函数需要传入的参数,返回调用函数的返回结果,属于立即执行函数。
  • apply():接受两个参数,第一个参数表示this要指向的对象,第二个参数表示调用函数所传入参数所组成的数组,返回调用函数的返回结果,属于立即执行函数。
  • bind():接受一个及其以上的参数,和call()一致,但是返回结果是一个函数,并且不会立即执行。

bind()返回的函数使用new作为构造函数时,绑定的this值会失效,this指向的是实例对象,但是传入的参数会生效。这是因为当使用bind()方法绑定上下文后,再通过new关键字调用这个函数,尽管bind()尝试固定this的值,但new操作符会覆盖这一绑定,强制将this指向新创建的实例。这是因为new操作符的核心特性之一就是创建一个新的对象并将其作为this上下文传递给构造函数。例如下面的代码:

function Person(name) {
    this.name = name;
    console.log(this);
}

Person.prototype.sayName = function() {
    console.log(this.name);
};

const boundPerson = Person.bind({ name: "bound" });

const personInstance = new boundPerson("instance"); // 这里的this不再是bind的第一个参数,而是新创建的实例
console.log(personInstance.name); // 输出 "instance"

12.用css画三角形

普通三角形:

.triangle {
  width: 0;
  height: 0;
  border-left: 50px solid transparent;
  border-right: 50px solid transparent;
  border-bottom: 100px solid red;
}

直角三角形:

.triangle {
  width: 0;
  height: 0;
  border-left: 50px solid red;
  border-right: 50px solid transparent;
  border-bottom: 100px solid transparent;
}

二.Vue 

1.为什么避免v-if与v-for一起使用?在Vue2与Vue3中的差异是什么?

原因:如果同时使用v-if和v-for的话,v-for的优先级高于v-if,导致v-for的循环元素会反复判断,例如循环10次数据,每一次循环都会做一次判断,做10次循环每一次循环都会判断10次,那么10次循环就会判断1000次,很浪费性能。

解决办法:

  • 在外层嵌套<template>标签:在外层嵌套<template>标签(不会生成真实的dom结点)进行判断,在内部做循环。
  • 利用computed属性:利用computed属性计算过滤需要渲染的数据后再循环渲染

<!--外层嵌套-->
<template v-if="isShow">
    <p v-for="item in items">
</template>

区别: 

        在vue3中不需要考虑该问题,因为已经将v-if的优先级改为高于v-for 

2.简述 pinia 与 vuex 的区别 

piniavuex
架构设计

设计更为简洁和模块化,每个 store 都是一个独立的实例,这使得状态管理更加解耦。Pinia 没有 mutation 的概念,直接通过 actions(支持同步和异步)来修改 state。

采用集中式的架构,有一个全局的 store 对象来管理应用的所有状态。Vuex 强制使用 actions 进行异步操作,并通过 mutations 修改状态,以确保状态变更的可追踪性。
初始化和使用更加直观,直接在 store 文件中定义 state、getters、actions,使用时可以直接从 setup 函数中导入并使用,支持 TypeScript 更友好。 需要在创建 store 时定义状态、mutations、actions 和 getters,使用时通过 mapState、mapGetters、mapActions 等辅助函数来绑定状态和方法。
状态持久化

虽然也能通过插件实现状态持久化,但默认情况下,如果需要将状态保存到本地存储,配置相对繁琐一些,不像 Vuex 有成熟的社区解决方案。

提供插件机制来实现状态持久化,如使用 vuex-persistedstate 插件将状态保存到 localStorage。
API和灵活性提供了更现代和简洁的API,强调易用性和开发体验,如自动的类型推导,直接在setup中使用 store 等特性,使得状态管理更加直观。API 较为成熟和稳定,但较为复杂,对于初学者来说学习曲线可能较陡峭。
维护和支持虽然不是Vue官方库,但由Vue的作者尤雨溪维护,得到了社区的广泛认可和积极发展,尤其在Vue 3的应用中推荐使用。 是 Vue 官方提供的状态管理库,长期得到维护和支持。

3.Vue中,watch和computed差异 

watchcomputed

目的和使用场景

主要用于监听数据变化并在变化时执行某些操作,可以处理异步操作,适用于需要在数据变化时执行副作用或复杂逻辑的场景,比如发起网络请求、更新DOM等。主要用于计算属性,基于依赖的数据自动计算并缓存结果,当依赖的数据发生变化时,会自动重新计算。适合于不涉及异步操作且结果可被缓存的场景,比如过滤列表、计算总价等。
缓存机制不提供缓存,每次依赖数据变化时都会触发回调函数执行,即使新旧值相同也不例外。具有缓存机制,只有当依赖的数据发生变化时,计算属性才会重新计算,否则直接返回缓存的结果,这使得计算属性在多次访问时能提高性能。
执行时机默认情况下,首次数据绑定时不会执行,仅在数据变化时执行。可以通过设置immediate: true使其在初始绑定时立即执行一次。

在初始化时和依赖数据变化时计算,计算属性的值在读取时计算。

异步支持支持异步操作,可以在回调函数中执行异步逻辑,如发送网络请求。不直接支持异步操作,因为它的值是基于依赖计算得出的,并且需要能够被缓存。
返回值接收一个函数作为回调,该函数有两个参数(新值和旧值),或者可以定义为一个对象,其中键是需要观察的表达式,值是对应回调函数。

通常返回一个值,可以是一个函数(getter),也可以是包含getter和setter的对象。

4.keep-alive 适用于什么应用场景? 

  • 列表与详情页面之间的切换:在从列表页面导航到详情页面,然后再返回到列表页面时,使用 keep-alive 可以保留列表页面的状态,包括滚动位置、筛选条件等,无需重新加载数据,提供流畅的用户体验。

  • tabs 切换:在一个含有多个 tab 的界面中,每个 tab 下可能是一个独立的组件。使用 keep-alive 可以让切换出去的 tab 组件保持活跃状态,当用户再次切换回来时,可以迅速恢复之前的状态,避免重新加载数据和渲染。

  • 性能优化:对于一些数据量大、渲染成本高的组件,使用 keep-alive 可以显著减少因频繁切换导致的性能开销,尤其是在移动设备上。

  • 状态保留:在需要保留用户输入或组件内部状态的场景下,使用 keep-alive 可以避免用户在返回时丢失已填写的信息或组件的临时状态。

5.Vue中,slot是什么?slot使用场景有哪些?

        slot 是一个用于组件间内容插槽的概念,它允许你在一个组件内部插入外部的模板内容。简而言之,slot充当了组件内部的一个占位符,使得父组件可以向子组件传递内容,这样可以让组件更加灵活和可复用。slot分为匿名slot、具名slot、作用域slot

应用场景:

  • 页面布局组件:如头部、侧边栏、主要内容区域等,可以使用具名slot来区分不同部分的内容,使得布局组件高度可定制。

  • 可复用组件:如对话框、卡片、列表项等,通过slot传递具体内容,使得组件能够在不同场景下复用,同时保持内容的多样性。

  • 封装第三方组件:在封装第三方UI库的组件时,可以使用slot来允许用户自定义部分内容,如按钮的文字、图标等。

  • 动态内容插入:当组件需要根据外部条件展示不同内容时,可以使用slot传递这些动态内容。

  • 表单组件:构建表单时,可以使用slot来插入自定义的表单项,同时通过作用域插槽传递表单项的验证信息、错误提示等。

6.Vue 项目中,可以在哪些生命周期内调用异步请求?实际项目中如何选择?

        可以在created()和mounted()两个生命周期函数内调用异步请求。在实际的项目中,要根据实际情况进行选择。一般情况下,优先选择created()进行调用,因为它可以更快地开始数据加载过程,提升用户体验。特别是当数据对页面初次渲染至关重要时,这能确保用户看到内容的速度最快。但如果异步请求的结果依赖于DOM元素(例如获取某个元素尺寸后发起请求),则应当在mounted中发起请求。

三.优化和其他

1.为确保前端展示数据的实时性,可以使用哪些技术?更推荐使用那种?

  • 轮询:客户端定期向服务器发送请求,询问是否有新的数据。这种方法简单易实现,但可能会造成不必要的请求,增加服务器压力,且实时性受限于轮询间隔。

  • 长轮询:客户端发送请求后,服务器不立即响应,直到有新数据产生或超时才返回响应。之后客户端立即发起新的请求,形成连续的连接。这种方式减少了无效请求,提高了实时性,但服务器仍需为每个连接保持资源,且在高并发下可能对服务器造成压力。

  • WebSocket:建立在TCP之上的全双工通信协议,允许服务器主动向客户端推送数据。一旦连接建立,双方都可以随时发送数据,实现实时双向通信。WebSocket是目前实现真正实时数据传输的最佳选择,特别适合需要低延迟、高频率交互的应用场景。

  • SSE:一种让服务器向浏览器发送实时更新的技术,只支持单向通信(服务器到客户端)。相对于WebSocket,实现更简单,对现有HTTP基础设施依赖较小,适合于只需要服务器推送数据到客户端的场景。

        在实际应用中,一般对于大多数需要实时数据更新的现代Web应用,WebSocket 是最推荐的技术,因为它提供了真正的双向通信,低延迟,且连接持久,能够满足大部分实时交互的需求。WebSocket特别适合聊天应用、在线游戏、实时交易系统等场景。如果实时性要求不是极高,或者实现复杂度和资源消耗是主要考虑因素,可以考虑使用 Server-Sent Events (SSE),特别是在只需单向数据流的应用中,它比WebSocket更简单易用,且对服务器资源的消耗相对较低。而对于简单的实时更新需求,且对旧浏览器兼容有要求的场景,长轮询 也是一个可行的选择,虽然不如WebSocket高效,但在特定条件下可以作为一种折中方案。

2.若一个页面上有大量的图片,加载很慢,你有哪些方法优化这些图片的加载? 

  • 使用webp格式:可以把图片转换为webp格式的图片,webp格式图片比jpg、png图片体积小很多,加载更快。
  • 懒加载(Vue Lazy Load): 使用Vue的懒加载插件,如vue-lazyload,来实现图片的按需加载。在Vue组件中,通过v-lazy指令绑定图片URL,图片只有在接近可视区域时才会开始加载。
  • 图片预加载(Vue Router 导航守卫): 利用Vue Router的导航守卫(如beforeRouteEnter或全局的守卫),在路由跳转前预加载即将访问页面的关键图片。
  • 缓存策略: 在Vue项目的服务器配置中设置合理的缓存策略,确保浏览器能够有效缓存图片资源,减少重复请求。

  • SVG图标: 将图标和简单图形替换成SVG格式,并直接在Vue组件的模板中使用,避免额外的HTTP请求。

3.Vue项目中,你尝试过哪些针对性能方面的优化?

  1. 组件懒加载: 使用Vue的异步组件特性或第三方库(如Vue Router的懒加载功能)来实现路由组件的懒加载。这样,只有当用户访问到特定路由时,相关组件才会被加载,减少首次加载时的资源体积。

  2. 图片懒加载: 利用如vue-lazyload这样的库实现图片懒加载,确保图片只在即将进入视口时才开始加载,减少页面初次加载时间。

  3. 优化Vue模板性能:避免在v-for中使用复杂的计算属性,尽量将计算移至循环外。使用key属性来帮助Vue识别列表中元素的身份,提高列表更新的性能。减少不必要的DOM操作,使用v-once指令缓存静态内容。

  4. 组件缓存: 利用<keep-alive>组件缓存不常变化的组件实例,减少不必要的渲染和初始化开销。

  5. 事件监听器的优化: 使用.once修饰符替代在每次组件更新时都添加新的事件监听器。

  6. 虚拟滚动: 对于长列表,使用虚拟滚动技术(如vue-virtual-scroller)只渲染可视区域内的列表项,大大减少DOM节点数量,提高滚动性能。

  • 16
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
前端面试时,项目可能会遇到各种问题。其一些常见的问题包括: - 兼容性问题:不同浏览器对于某些CSS属性或JS方法的支持可能存在差异,导致页面在不同浏览器上显示效果不一致。 - 性能问题:页面加载速度慢、渲染迟缓等问题都会影响用户的体验。 - 响应式设计问题:在不同设备上展示页面时,可能会出现布局错乱、字体大小不合适等问题。 - 数据交互问题:与后端接口对接时,可能会出现数据格式不一致、请求超时等问题。 - 页面安全性问题:如XSS(跨站脚本攻击)、CSRF(跨站请求伪造)等安全漏洞可能会对页面造成影响。 解决这些问题的方法和技巧有很多,以下是一些常用的方法: - 使用CSS预处理器(如Less、Sass)来简化样式的编写,并提供一些方便的功能(如变量、嵌套、混合等)。 - 使用代码压缩工具(如UglifyJS、CSSNano)来压缩JS和CSS文件,以减少文件大小和网络传输时间。 - 使用缓存策略(如HTTP缓存、LocalStorage)来提高页面加载速度和用户体验。 - 使用性能分析工具(如Google PageSpeed Insights、Lighthouse)来评估和改进页面的性能。 - 使用响应式设计框架(如Bootstrap、Foundation)来简化响应式设计的开发过程,并提供一致的用户体验。 - 使用安全性工具(如CSP、X-XSS-Protection)来防止页面受到恶意攻击。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值