2023年前端面试总结:常见前端面试题

1,642 阅读18分钟

以下是一些前端常见面试题:

1. 解释一下什么是盒模型?如何设置盒模型的尺寸?

  • 盒模型是指在Web页面中,每个元素都被看作是一个矩形的盒子。这个盒子由四个部分组成:内容区域(content)、内边距(padding)、边框(border)和外边距(margin)。其中,内容区域包含了元素实际显示的内容,内边距是在内容区域和边框之间留出的空白区域,边框是围绕内容和内边距的线条,而外边距则是盒子与周围元素之间的空白区域。

  • 设置盒模型的尺寸可以使用CSS中的box-sizing属性。box-sizing属性有两个可选值:content-box和border-box。默认值为content-box,表示盒子大小只包括内容区域,不包括内边距、边框和外边距。而当box-sizing的值为border-box时,表示盒子大小包括内容区域、内边距和边框,但不包括外边距。因此,可以通过设置box-sizing属性来改变盒模型的尺寸计算方式,以实现更精准的布局效果。

2. 解释一下什么是闭包(closure)?它有什么作用?

  • 闭包(closure)是指在一个函数内部定义的函数可以访问该函数的变量和参数,即使在该函数执行完毕之后仍然可以访问这些变量和参数。换句话说,闭包是一种特殊的函数,它不仅可以访问自身作用域中的变量和参数,还可以访问包含它的函数的作用域中的变量和参数。
闭包有以下几个作用:
  1. 实现模块化:使用闭包可以实现模块化,将变量和方法封装在一个独立的作用域内,避免命名冲突和全局污染。

  2. 保存状态:闭包可以保存函数的状态,因此可以在函数执行完毕后继续保留这些状态,供下次调用时使用。

  3. 面向对象编程:通过闭包可以实现面向对象编程的基本概念,如私有属性、公共属性和方法等。

  4. 延迟执行:使用闭包可以实现延迟执行,将要执行的代码块封装到一个函数中,并返回该函数,待需要执行时再调用该函数。

  • 需要注意的是,由于闭包会引用外部函数的变量和参数,而这些变量和参数在函数执行完毕后通常应该被销毁,如果没有妥善处理可能会导致内存泄漏问题。因此,在使用闭包时需要注意内存管理,及时释放对外部变量和参数的引用。
// 场景:获取员工基本工资(基础工资 + 绩效工资)

// 需求描述:同级别员工基本工资不变,绩效工资随着业绩改变 这样基础工资会重复参与计算

// 基础工资变量base; 绩效工资:performance

function makeSalary (base) {

  return function (performance) {

    return base + performance

  }

}

// 这样保证同级别员工基础工资计算不重复,只要知道绩效工资就可以了

let salary = makeSalary(12000);

console.log(salary(3000));

3. 谈谈对CSS选择器及优先级的理解。

  • CSS选择器用于指定需要样式化的HTML元素,它可以根据不同的选择器类型和组合形式来匹配特定的元素,从而对其应用相应的样式。
常见的CSS选择器类型包括:
  1. 元素选择器:通过元素的标签名来匹配元素,例如p、div、span等。

  2. 类选择器:以点号(.)开头,用于匹配具有相同类名的元素,例如.class。

  3. ID选择器:以#符号开头,用于匹配具有唯一ID属性的元素,例如#id。

  4. 属性选择器:用于匹配具有相同属性名或属性值的元素,例如[attr]、[attr="value"]等。

  5. 伪类选择器:用于匹配处于某种状态或位置的元素,例如:hover、:nth-child()等。

  6. 后代选择器:用于匹配某个元素的后代元素,例如div p、ul li等。

  7. 相邻兄弟选择器:用于匹配紧随在另一个元素后面的元素,例如h1 + p。

CSS选择器的优先级是指当多个选择器作用于同一个元素时,决定哪个样式规则会被应用。CSS选择器的优先级按照以下顺序进行排序:
  1. !important:优先级最高,无法被覆盖。

  2. 行内样式:应用于元素上的样式,优先级次于!important。

  3. ID选择器:使用了ID选择器的样式,优先级次于行内样式。

  4. 类选择器、属性选择器、伪类选择器:使用这些选择器设置的样式,优先级次于ID选择器。

  5. 元素选择器、伪元素选择器:使用这些选择器设置的样式,优先级次于类选择器、属性选择器、伪类选择器。

  6. 通配符(*)、子串匹配选择器、属性值前缀选择器、属性值包含选择器、属性值后缀选择器、属性值完全匹配选择器、伪元素选择器:使用这些选择器设置的样式,优先级最低,只有在其他选择器没有匹配到时才会生效。

  • 需要注意的是,如果两个选择器优先级相同,则后面出现的样式规则会覆盖前面的样式规则。同时,如果样式规则中存在继承属性,它们的优先级通常比较低,需要慎重使用。

4. 什么是CSS预处理器?列举几个常用的CSS预处理器。

  • CSS预处理器是一种将类似于编程语言的语法用于CSS样式表中的工具,它可以增强CSS的功能和可读性,提高CSS开发效率。通常在编写CSS代码时,需要重复书写大量的选择器、属性和值,这会导致代码冗长、维护困难,而使用CSS预处理器可以通过定义变量、嵌套规则、使用函数等方式来简化CSS代码的编写,使得代码更加模块化和易于维护。

以下是几个常用的CSS预处理器:

  1. Sass:Sass是最受欢迎的CSS预处理器之一,它支持变量、嵌套规则、混合(Mixin)、函数等功能,并且有很多开源框架和工具库可供使用。

  2. Less:Less是另一个流行的CSS预处理器,与Sass类似支持变量、嵌套规则、Mixin等功能,但其语法较为简单,易于上手。

  3. Stylus:Stylus是JavaScript编写的CSS预处理器,具有灵活的语法和强大的动态功能,可以通过JS函数来设置CSS属性值。

  4. PostCSS:PostCSS不同于传统的CSS预处理器,它是一个基于插件的工具,可以让开发者利用JavaScript编写自己的插件,进而扩展CSS的功能和语法。

  • 这些CSS预处理器都具有各自的优缺点和适用场景,开发者可以根据项目特点和个人喜好选择适合自己的预处理器。

5. 如何解决跨域问题?列举几种方法。

跨域问题是指由于浏览器的同源策略(Same-Origin Policy),导致不能在不同域名、协议或端口之间直接进行数据交互。为了解决这个问题,常用的方法有以下几种:

  1. JSONP:JSONP利用script标签没有跨域限制的特性,在服务端动态生成一个JavaScript函数,并将需要传递的数据作为参数传入函数中,最终将整个函数作为脚本返回给客户端,从而实现跨域请求。

  2. CORS:跨域资源共享(CORS)是一种通过修改HTTP头部来实现跨域请求的技术。对于支持CORS的服务器,可以在响应头中添加Access-Control-Allow-Origin字段来允许特定域名的请求访问该资源,从而实现跨域请求。

  3. 代理:代理方式是指在同一域下搭建一个代理服务器,将浏览器的请求转发到目标服务器上,并将响应结果再返回给浏览器。使用代理方式可以规避浏览器的跨域限制,但需要额外搭建一个代理服务器。

  4. Nginx反向代理:Nginx可以设置反向代理,将浏览器的请求转发到目标服务器上,并将响应结果再返回给浏览器。与前面的代理方式不同,Nginx反向代理是在服务端进行配置,无需额外搭建代理服务器,并且可以有效提升请求速度和安全性。

  • 以上的方法都有各自的优缺点和适用场景,开发者可以根据具体情况选择适合自己的解决方案。

6. 请简述你对HTTP协议的理解。

HTTP协议(Hypertext Transfer Protocol)是一种用于传输超文本的协议,它是Web应用程序的基础之一。HTTP协议通过客户端和服务器之间的请求和响应来交换数据,并定义了客户端和服务器之间如何进行通信,以及如何处理错误和异常情况。以下是对HTTP协议的一些简述:

  1. HTTP协议是基于TCP/IP协议之上的应用层协议,使用80端口进行传输。

  2. HTTP通常是无状态的,即每次请求都是独立的,服务器不会保存客户端的状态信息。为了解决这个问题,HTTP提供了Cookie和Session机制。

  3. HTTP请求由三部分组成:请求行、请求头部和消息主体。其中,请求行包括请求方法、请求URL和协议版本;请求头部包括请求报文中的各种属性和值;消息主体则是可选的,用于传输数据内容。

  4. HTTP响应由三部分组成:状态行、响应头部和消息主体。其中,状态行包括协议版本、状态码和状态描述;响应头部同样包括各种属性和值;消息主体则是可选的,用于传输响应内容。

  5. HTTP协议支持多种请求方法,包括GET、POST、PUT、DELETE、HEAD、OPTIONS等,不同的请求方法对应着不同的操作。

  6. HTTP协议支持缓存,可以通过设置Cache-Control、Expires等响应头部属性来控制数据的缓存策略。

  • HTTP协议是Web开发中非常重要的基础知识,理解HTTP协议有助于开发者更好地理解Web应用程序的工作原理,也可以帮助开发者更高效地进行Web应用程序的调试和优化。
6.1 http 与 https 的区别

HTTP(Hypertext Transfer Protocol)和HTTPS(HyperText Transfer Protocol Secure)是两种不同的网络传输协议,主要区别在于:

  1. 安全性:HTTP通信使用明文传输数据,容易被黑客窃听、篡改或伪造。而HTTPS通过SSL/TLS协议对数据进行加密,可以保证数据传输过程中的机密性、完整性和身份验证。

  2. 端口号:HTTP默认使用80端口进行传输,而HTTPS默认使用443端口进行传输。

  3. 证书认证:HTTPS通信需要使用SSL/TLS证书对服务器进行认证,确保客户端与服务器之间建立的连接是安全可靠的。而HTTP不存在这种认证机制,无法确定请求的真实来源。

  4. 性能开销:HTTPS通信需要进行加密、解密操作,会增加服务器的负担和通信延迟,因此相对于HTTP来说会有一定的性能开销。

  • 综上所述,HTTPS相对于HTTP来说更加安全可靠,但同时也带来了一些额外的性能开销。开发者在选择HTTP还是HTTPS时,需要根据具体情况和需求进行权衡和选择。

7. 解释一下什么是事件委托(event delegation)?以及它的使用场景和实现方式。

事件委托是一种基于事件冒泡机制的技术,它使得开发者可以利用JavaScript在父元素上处理子元素的事件。通常情况下,为每个子元素添加事件监听器会导致大量的代码和内存消耗,而使用事件委托则可以将所有的事件处理代码集中到父元素上,从而提高性能和减少代码量。

事件委托的原理是:当子元素触发某个事件时,该事件会向上冒泡到父元素,父元素就可以捕获该事件,并根据事件的目标对象判断是否需要进行相应处理。

事件委托的使用场景主要包括:

  1. 列表或表格类页面:例如商品列表、数据表格等,可以通过给父元素绑定事件来监听子元素的点击事件,从而减少事件绑定的次数。

  2. 动态生成的元素:如果需要对动态生成的元素进行事件绑定,可以通过事件委托的方式来解决。

  3. 性能优化:因为事件委托只需要绑定一个事件处理函数,因此可以减少事件绑定的次数,提高页面的性能表现。

实现事件委托的方式有多种,其中比较常见的两种方式是:

  1. 使用事件冒泡机制:通过在父元素上绑定事件监听器,并在事件处理函数中根据事件的目标对象进行相应的处理。

  2. 使用代理机制:通过在父元素上绑定一个特定的事件(如click),然后在事件处理函数中通过event.target属性获取到触发事件的目标对象,从而进行相应的处理。

  • 需要注意的是,事件委托虽然能够减少事件绑定次数,但也有可能导致一些意外的行为(例如事件冒泡到了不应该处理的元素上),因此在使用事件委托时需要注意事件传播的方向和目标对象。

8. 你如何进行网站性能优化?

网站性能优化是一项非常重要的工作,它可以提升网站的响应速度、用户体验和搜索引擎排名。下面是我进行网站性能优化时所采取的一些措施:

  1. 压缩和合并文件:对CSS、JavaScript和HTML等静态资源进行压缩和合并,减少HTTP请求次数和传输时间。

  2. 利用缓存:通过设置缓存策略(如Cache-Control、Expires、ETag等)来减少服务器的负担和网络传输时间。

  3. 图片优化:对图片进行压缩和裁剪,使用WebP格式或SVG矢量图等优化方案,以减小页面加载时间。

  4. DNS预解析:通过在head元素中添加dns-prefetch标签,让浏览器预先解析域名,加快页面加载速度。

  5. 延迟加载:通过使用懒加载技术,将页面上不必要的内容延迟加载,减少初始加载时间。

  6. 代码优化:优化JavaScript代码、CSS代码和HTML代码,避免使用冗长的代码和多余的样式。

  7. 服务端优化:优化服务器配置和代码,采用CDN、负载均衡等技术,提高服务器的响应速度和稳定性。

  8. 移动设备优化:对移动设备进行适配,采用响应式布局、禁用不必要的功能等方案,提高移动设备的用户体验。

  • 综上所述,进行网站性能优化需要从多个方面入手,需要根据具体情况采取相应的措施。同时,也需要持续监测和分析网站的性能指标,及时调整优化策略,以达到最佳的性能表现。

9. 请谈谈你对React或Vue框架的理解,以及在项目中的应用经验。

React和Vue都是流行的开源JavaScript前端框架,它们提供了一种组件化的方式来构建Web应用程序,并且在性能、可维护性和扩展性等方面都具有很好的表现。下面是我对React和Vue的理解和我的项目应用经验:

React: React是一个由Facebook开发的JavaScript库,主要用于构建大型Web应用程序。React采用虚拟DOM技术,可以最小化渲染次数,从而提高性能和效率。React的核心思想是“组件化”,通过将UI划分为独立的组件,使得代码更加模块化和易于维护。我在前公司的项目中使用了React来实现多个单页面应用(SPA),例如社交网络、在线教育平台等。使用React可以快速构建页面,方便进行状态管理和组件复用。同时,React还有大量的第三方组件和工具库可以使用,例如Redux、React Router、Axios等。

Vue: Vue是一个由尤雨溪开发的JavaScript框架,也是一个轻量级的渐进式框架。与React类似,Vue也采用了组件化的思想,但其语法更加简洁易学,适合新手入门。Vue也支持虚拟DOM技术,并提供了响应式数据绑定、指令和过滤器等特性,可以大大提高Web开发的效率。我在另一个项目中使用了Vue框架来开发一个网站,并利用了Vue的路由、状态管理和第三方组件等功能。使用Vue可以让代码更加简洁、易于维护和扩展。

  • 总体来说,React和Vue各有优缺点,在不同的项目中选择合适的框架可以提高开发效率和质量。
React和Vue框架理解及应用经验

在我看来,React和Vue都是非常流行的前端框架,它们都有着良好的组件化、数据驱动视图等特性。相比之下,React更加注重组件化和函数式编程思想,而Vue则更加注重模板化和响应式数据绑定。

在我的项目经验中,我曾经使用React框架来开发一个企业级管理系统。我们采用了Redux来进行状态管理,并且使用了React-Router来实现路由控制。在这个项目中,我主要负责开发一些复杂的交互组件,例如表格、树形控件等。通过使用React的组件化思想,我们可以将这些复杂的交互组件拆分成多个小组件,并且通过props和state进行数据传递和状态管理。这样不仅可以提高代码复用率,还可以方便地进行单元测试。

另外,在另一个项目中,我也曾经使用Vue框架来开发一个在线教育平台。我们采用了Vuex来进行状态管理,并且使用了Vue-Router来实现路由控制。在这个项目中,我主要负责开发一些复杂的表单页面和视频播放器等功能模块。通过使用Vue的模板化思想和响应式数据绑定机制,我们可以方便地实现表单页面的数据双向绑定,并且可以快速地更新UI界面。

总体而言,在我的项目经验中,React和Vue都是非常优秀的前端框架,并且都具有各自独特的特点和优势。具体选择哪个框架取决于具体项目需求以及团队技术栈等因素。

10. 如何实现一个拖拽功能?

实现一个拖拽功能可以通过以下步骤来完成:

  1. 给拖拽元素添加mousedown事件监听器,在该事件处理函数中记录下鼠标点击的位置和拖拽元素的初始位置。

  2. 给document对象添加mousemove事件监听器,在该事件处理函数中计算出鼠标移动的距离,更新拖拽元素的位置。

  3. 给document对象添加mouseup事件监听器,在该事件处理函数中取消mousemove事件监听器,并在拖拽结束时进行一些处理(如触发回调函数、更新数据状态等)。

下面是一个简单的实现拖拽功能的代码示例:

<div id="drag-element">拖拽元素</div>

<script>
  const dragElement = document.getElementById('drag-element');
  let startX, startY, initialX, initialY;

  function onMouseDown(event) {
    // 记录鼠标点击时的位置和拖拽元素的初始位置
    startX = event.clientX;
    startY = event.clientY;
    initialX = dragElement.offsetLeft;
    initialY = dragElement.offsetTop;

    // 绑定mousemove和mouseup事件
    document.addEventListener('mousemove', onMouseMove);
    document.addEventListener('mouseup', onMouseUp);
  }

  function onMouseMove(event) {
    // 计算鼠标移动的距离
    const deltaX = event.clientX - startX;
    const deltaY = event.clientY - startY;

    // 更新拖拽元素的位置
    dragElement.style.left = `${initialX + deltaX}px`;
    dragElement.style.top = `${initialY + deltaY}px`;
  }

  function onMouseUp() {
    // 取消mousemove和mouseup事件绑定
    document.removeEventListener('mousemove', onMouseMove);
    document.removeEventListener('mouseup', onMouseUp);
  }

  dragElement.addEventListener('mousedown', onMouseDown);
</script>
  • 需要注意的是,上述代码只是一个基本的实现方式,可能会存在一些问题(如边界检测、多个拖拽元素等),在实际项目应用中需要根据实际需求进行相应的调整和优化。

这些是前端面试中较为基础的问题,当然还有很多更深入的问题需要根据岗位要求而定。