Day3—前端面试题(综合篇)

前端面试题(综合篇)

1.讲讲事件循环

在事件循环中,所有的任务可以分为同步任务和异步任务,它们的执行方式有所不同。

(1)同步任务会直接进入主线程执行,不会被阻塞。

(2)异步任务会被放入事件表(Event Table),并注册相应的回调函数到事件队列(Event Queue)。当满足触发条件时,这些异步任务的回调函数会被移入执行队列(Execution Queue)中等待执行。

主线程在执行同步任务的同时,会不断地检查执行队列,如果执行队列中有待执行的任务,主线程会将它们移入执行栈(Execution Stack)中执行。这个过程不断循环,即为事件循环。

下面结合一段代码来理解上述概念:

// 同步任务
console.log("同步任务开始");

// 异步任务1:使用setTimeout模拟一个异步任务
setTimeout(function() {
  console.log("异步任务1完成");
}, 2000); // 2秒后执行回调函数

// 异步任务2:使用Promise模拟另一个异步任务
const promiseTask = new Promise(function(resolve, reject) {
  setTimeout(function() {
    resolve("异步任务2完成");
  }, 1000); // 1秒后异步任务完成
});

promiseTask.then(function(result) {
  console.log(result);
});

console.log("同步任务结束");

// 输出结果顺序为:
// 同步任务开始
// 同步任务结束
// (等待2秒)
// 异步任务2完成
// 异步任务1完成

在这段代码中,我们有一些同步任务和异步任务。

  • 同步任务会立即执行,不会被阻塞。所以 “同步任务开始” 和 “同步任务结束” 会立即输出。
  • 异步任务1 使用 setTimeout 模拟,会在2秒后输出 “异步任务1完成”。
  • 异步任务2 使用 Promise 模拟,会在1秒后输出 “异步任务2完成”。

在执行过程中,异步任务1和异步任务2被放入事件表,并注册了相应的回调函数到事件队列。当所有同步任务执行完毕后,主线程会不断地检查事件队列,将其中的任务移入执行栈执行。所以 “异步任务2完成” 会先输出,然后是 “异步任务1完成”。

2.讲讲跨域

跨域(Cross-Origin)指的是在 Web 开发中,当一个页面的脚本尝试去访问另一个源(域、协议或端口)的资源时所发生的一种情况。由于浏览器的同源策略(Same-Origin Policy),默认情况下,页面中的 JavaScript 代码只能与同一源下的资源进行交互,而无法直接访问其他源的资源。

同源策略的存在是出于安全考虑,它可以防止恶意网站通过脚本获取用户的敏感信息,比如 Cookie、LocalStorage 等。但有时候,我们确实需要与其他源的资源进行交互,比如在前后端分离的情况下,前端页面需要获取后端 API 的数据,这就涉及到了跨域。

常见的跨域场景:

  1. 前后端分离开发:在前后端分离的开发模式下,前端项目通常运行在一个不同的域名或端口下,与后端 API 服务器不在同一个源(origin)下,因此会遇到跨域问题。

    解决方案:在后端服务中配置 CORS(Cross-Origin Resource Sharing),允许前端应用的域名或者端口访问后端 API。或者使用反向代理服务器,在同一域名或端口下转发请求。

  2. 跨子域请求:例如,一个页面是从 www.example.com 加载的,而 API 接口却在 api.example.com 上,这种情况也会触发跨域问题。

    解决方案:在后端服务中配置 CORS,允许跨域请求来自指定的子域名。

  3. 跨协议请求:例如,一个页面是通过 HTTPS 加载的,但是 API 接口却是通过 HTTP 提供的,这也会触发跨域问题。

    解决方案:由于浏览器对跨协议请求的限制较强,通常建议统一使用 HTTPS 协议,以保障数据传输的安全性。

  4. 跨端口请求:即使是在同一台服务器上,如果前端页面运行在一个端口,而后端 API 服务运行在另一个端口,也会被浏览器视为跨域请求。

    解决方案:同样在后端服务中配置 CORS,允许前端应用的端口访问后端 API。

  5. 跨文档访问(Cross-document communication):例如,通过 <iframe> 或者在一个窗口中打开另一个窗口,如果它们的源不同,就会涉及到跨域访问。

    解决方案:可以使用 postMessage API 进行跨窗口通信,或者在目标页面中设置合适的 CORS 头部来允许跨域访问。

  6. 第三方资源引入:例如,在页面中引入了来自其他网站的 JavaScript、CSS 或者图片等资源,如果这些资源的域名与当前页面不一致,就会产生跨域问题。

    解决方案:如果资源是可以下载并重新托管的,可以将资源下载到本地再引入;如果资源是不可更改的,可以使用服务器端代理,将资源代理到当前域名下。

  7. 跨站点脚本攻击(Cross-Site Scripting, XSS):虽然不是正常的跨域请求,但 XSS 攻击也是一种跨域问题,它利用了浏览器不同源策略的弱点,在一个网站上执行恶意脚本来窃取用户信息等。

    解决方案:避免直接执行来自用户输入的脚本,对用户输入进行合适的过滤和转义,使用 Content Security Policy(CSP)等安全机制来限制脚本的执行。

3.webpack和vite的区别

Webpack 和 Vite 是两种前端构建工具,它们在构建过程、开发体验和性能表现等方面有一些区别:

  1. 构建过程
    • Webpack:Webpack 是一种基于任务(task)的构建工具,它通过配置文件定义一系列任务和处理器,如编译 JavaScript、处理 CSS、压缩图片等,然后按照配置文件的定义逐个执行这些任务,最终生成构建产物。
    • Vite:Vite 是一种基于原生 ES 模块的构建工具,它利用浏览器原生支持的 ES 模块特性,在开发时不需要预先构建整个应用,而是按需编译、按需加载,以更快的速度启动开发服务器和构建应用。
  2. 开发体验
    • Webpack:Webpack 在开发时通常需要较长的构建时间,每次修改代码都需要重新构建整个应用,因此开发体验可能不够流畅,特别是对于大型应用。
    • Vite:Vite 利用了浏览器原生的 ES 模块加载特性,可以快速地启动开发服务器,且在修改代码时只需重新编译修改的部分,因此开发体验更加流畅,可以实现毫秒级的热更新。
  3. 性能表现
    • Webpack:Webpack 的构建速度通常较慢,尤其是在处理大型应用时,因为它需要对整个应用进行重新构建。
    • Vite:Vite 的构建速度通常较快,因为它只需要编译和加载修改的部分,而不需要重新构建整个应用,因此在开发时能够实现更快的热更新和启动开发服务器。

总的来说,Webpack 更适用于构建复杂的大型应用,而 Vite 更适用于快速启动开发服务器和提供流畅的开发体验,特别是对于小型应用和中小型团队来说。

4.HTTP缓存

HTTP 缓存是一种在 Web 开发中用于提高性能和减少网络流量的技术,它通过在客户端(浏览器)和服务器之间缓存资源的副本来减少对服务器的请求。HTTP 缓存通常可以分为两种类型:浏览器缓存和代理服务器缓存。

  1. 浏览器缓存
    • 强缓存:浏览器在请求资源时会先检查是否存在强缓存,如果存在且未过期,浏览器直接从缓存中获取资源,不发送请求到服务器。强缓存通常通过设置响应头中的 Cache-ControlExpires 字段来实现。
    • 协商缓存:当资源的强缓存过期或不存在时,浏览器会发送一个带有条件的请求到服务器,服务器根据请求头中的 If-Modified-SinceIf-None-Match 字段验证资源是否发生了变化。如果资源未发生变化,则返回状态码 304 Not Modified,浏览器从缓存中获取资源。协商缓存通常通过设置响应头中的 Last-ModifiedETag 字段来实现。
  2. 代理服务器缓存
    • 代理服务器(如 CDN)也可以缓存资源,当请求到达代理服务器时,代理服务器会根据一定的规则来判断是否缓存响应。代理服务器缓存可以减少网络流量,并且能够为全球范围内的用户提供更快的访问速度。

通过合理地配置缓存策略,可以有效地提高网站的性能和用户体验。不过需要注意的是,缓存也可能会带来一些问题,如缓存过期导致的资源不一致性,因此需要根据实际情况来选择合适的缓存策略。

5.原型链

原型链是 JavaScript 中用于实现继承和属性查找的重要机制。每个 JavaScript 对象都有一个原型(prototype),原型又是一个对象,对象之间通过原型形成了链式结构,即原型链。

  1. 对象和原型
    • 在 JavaScript 中,几乎所有的对象都是通过构造函数创建的,每个构造函数都有一个 prototype 属性,指向一个原型对象。
    • 对象通过 __proto__ 属性(或 Object.getPrototypeOf() 方法)指向自己的原型对象。
  2. 继承和属性查找
    • 当我们访问一个对象的属性时,如果该属性不存在,则 JavaScript 引擎会沿着原型链向上查找,直到找到属性或者到达原型链的顶端(即 Object.prototype)为止。
    • 这样就实现了继承的效果,子对象可以共享父对象的属性和方法。
  3. 原型链的终点
    • 原型链的终点是 Object.prototype,它是 JavaScript 中所有对象的原型链的顶端。
    • Object.prototype 的原型是 null,表示它没有原型,是原型链的终点。

例如,我们创建一个对象并访问它的属性:

// 创建一个对象
var obj = {
  name: 'Alice'
};
// 访问属性
console.log(obj.name); // 'Alice'
console.log(obj.age); // undefined

当我们访问 obj 的属性时,如果属性存在,则直接返回属性值;如果属性不存在,则沿着原型链向上查找,直到找到或者到达原型链的顶端。在这个例子中,obj 对象的原型是 Object.prototype,因此当访问 age 属性时返回 undefined

6.节流和防抖

节流(throttling)和防抖(debouncing)是两种常用的优化性能的方法,特别是在处理频繁触发的事件时,比如滚动事件、resize 事件等。

  1. 节流(throttling)

    • 节流的原理是在一定的时间间隔内只执行一次函数,即使事件被触发多次。
    • 通常在事件持续触发时,将函数调用限制在指定的时间间隔内,避免频繁触发造成性能问题。
    • 节流可以通过定时器实现,在每次触发事件时设置一个定时器,在定时器到期之前不执行函数,当定时器到期时执行函数并重新设置定时器。
  2. 防抖(debouncing)

    • 防抖的原理是在一定的时间间隔内只执行一次函数,但是函数执行的时机是在事件停止触发之后。
    • 当事件持续触发时,函数不会立即执行,而是等待一段时间(比如 100ms),如果在这段时间内事件没有再次触发,则执行函数;如果事件再次触发,则重新等待一段时间。
    • 防抖可以通过定时器实现,在事件触发时设置一个定时器,在定时器到期之后执行函数,如果在定时器到期之前再次触发事件,则重新设置定时器。

    代码示例

    // 节流函数
    function throttle(func, delay) {
      let timer = null;
      return function() {
        if (!timer) {
          timer = setTimeout(() => {
            func.apply(this, arguments);
            timer = null;
          }, delay);
        }
      };
    }
    
    // 防抖函数
    function debounce(func, delay) {
      let timer = null;
      return function() {
        clearTimeout(timer);
        timer = setTimeout(() => {
          func.apply(this, arguments);
        }, delay);
      };
    }
    
    

    7.XSS和CSRF

    XSS(Cross-Site Scripting)和 CSRF(Cross-Site Request Forgery)是两种Web应用程序中常见的安全漏洞,它们都可能导致恶意攻击者对用户数据进行窃取或篡改。

    1. XSS(跨站脚本攻击)
      • XSS 攻击是一种通过在受信任的网站上注入恶意脚本代码,然后让用户在浏览器中执行这些恶意脚本的攻击方式。
      • 攻击者可以在受害者的浏览器中执行恶意脚本,盗取用户的 Cookie、SessionID 等敏感信息,或者在用户登录状态下执行一些恶意操作,如发送恶意请求、篡改页面内容等。
      • XSS 攻击分为三种类型:存储型(存储在服务器端,如评论区)、反射型(恶意脚本作为 URL 参数发送到服务端,服务端返回并执行)和 DOM 型(恶意脚本通过 URL 参数等方式直接执行在客户端)。
    2. CSRF(跨站请求伪造)
      • CSRF 攻击是一种利用用户已登录的身份在用户不知情的情况下,以用户的名义执行非预期的操作的攻击方式。
      • 攻击者通常会诱使用户点击一个恶意链接,该链接会触发一个向目标网站发送请求的操作,而用户在点击链接后,已经登录的状态下会自动携带上自己的身份凭证,导致服务器无法区分是否是合法用户的请求。
      • 攻击者利用 CSRF 漏洞可以执行一系列恶意操作,比如在用户账户下进行转账、更改密码、发送消息等。

    防御 XSS 和 CSRF 攻击的常用方法包括:

    • XSS 防御:对用户输入和输出进行严格的过滤和转义,不信任的内容不要直接插入到页面上,使用 Content Security Policy(CSP)等安全策略来限制页面中脚本的执行。
    • CSRF 防御:使用 CSRF Token 来防御 CSRF 攻击,服务器在返回页面时,向页面中插入一个随机的 Token,并要求在提交表单或者执行敏感操作时必须携带这个 Token,以确认请求的合法性。同时,使用同源策略、使用验证码、检查 Referer 头等方法也能够一定程度上减轻 CSRF 攻击的风险。
  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爪洼守门员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值