Oi~这里肯定有你不会的面试题

739 阅读12分钟

最近面试了三家公司,记录复盘了一下我没有回答出的地方,对自己的知识面进行查漏补缺,因为各方面都有涉及,并不是系统性的整理,所以希望对大家有所帮助,别忘点个赞,感谢各位靓仔靓女。

HTML

href与src之间的区别

  • src是指向物件来源的地址是引入通常在img,script,iframe元素上使用;href是超文本引用,指向需要连接的地方。
  • 可替换的元素上使用src,引入资源嵌套当前位置,href用于在文档和外部资源建立一个关系。
  • 在请求src资源时,会暂停该资源加载,编译,执行完毕;而浏览器解析href资源时,不会停止对当前文档的处理。

image标签中alt和title的区别

image标签alt可以用图片无法显示时,用文本来占位。title属性时用户鼠标悬停在图像上时,可以显示一个小的文本框,用于描述图片。

iframe相关的知识

<iframe> 元素在 HTML 中用于在当前页面内嵌入另一个文档。它常用于嵌入外部内容,比如视频、广告、其他网页或第三方应用等。

基本用法
<iframe src="https://www.example.com" width="600" height="400" frameborder="0"></iframe>

  • src: 指定要嵌入的资源的 URL。
  • widthheight: 设置 iframe 的宽度和高度。
  • frameborder: 控制是否显示 iframe 边框。0 表示没有边框,1 表示有边框。
常用属性
  1. src: 嵌入的内容的 URL(可以是外部链接或同源页面)。
  2. name: 指定一个名称,允许其他窗口或表单通过 target="iframe_name" 指定在哪个 iframe 中打开链接。
  3. sandbox: 启用额外的安全限制。允许限制 iframe 内部的行为,比如禁用表单提交、脚本执行等。
  4. allow: 允许的权限设置,比如 allow-scriptsallow-same-origin 等,限制或允许某些功能。
  5. loading="lazy": 延迟加载 iframe,只在用户需要时加载,提高性能。
iframe 的常见用途
  1. 嵌入第三方内容: 通过 iframe 嵌入来自外部服务的内容,例如视频(YouTube)、地图(Google Maps)或广告。
  2. 跨域内容显示: iframe 提供了独立的上下文,可以展示跨域资源,避免直接加载外部内容对主页面的影响。
  3. 子页面与主页面分离: 当你希望将页面的一部分单独加载或管理时,可以使用 iframe,例如嵌套页面,在线支付、用户登录等。
  4. 浏览器兼容性: 通过 iframe 可以有效隔离页面的行为,解决不同浏览器对某些功能的兼容性问题。
优点
  1. 跨域隔离:
    • iframe 提供了浏览器级别的隔离,可以在主页面中嵌入来自不同源的内容,而无需担心跨域访问问题。这样可以避免不同来源的 JavaScript 相互干扰。
    • 例如,嵌入外部站点的内容时,iframe 会创建一个隔离的上下文,保证外部网站的脚本不会直接访问主页面的 JavaScript 环境。
  2. 避免主页面影响:
    • iframe 可以将第三方内容隔离开,避免影响主页面的样式、布局和脚本。例如,广告、社交插件、外部小工具等。
  3. 内容的独立性:
    • 嵌入的 iframe 内容可以是独立的文档(带有自己的样式、JavaScript、框架等),不会与父页面发生冲突。这使得处理动态内容或需要单独控制的部分变得简单。
  4. 加载控制:
    • 通过 iframe 可以延迟加载资源(例如,通过 loading="lazy" 属性),减少页面初次加载时的性能压力。
  5. 浏览器兼容性:
    • iframe 是 HTML 标准的一部分,广泛支持,并且能有效解决不同浏览器对某些特性的支持差异。
缺点
  1. 性能问题:
    • 使用 iframe 会增加页面的请求数量和渲染复杂性。每个 iframe 都会作为一个独立的浏览上下文来加载和渲染,可能会增加浏览器的负担,影响页面性能。
    • 如果页面中嵌套多个 iframe,可能会导致过多的资源消耗,尤其是在移动端设备上。
  2. 响应式设计问题:
    • 由于 iframe 的内容可能来自不同源,它的大小和布局可能无法与父页面的响应式设计完全兼容。需要使用 iframe 内的 CSS 或 JavaScript 来调整它的尺寸和布局,增加了开发复杂度。
  3. 安全问题:
    • iframe 中嵌入的外部内容可能会带来安全隐患。例如,恶意的第三方内容可能利用 iframe 进行钓鱼攻击或加载恶意脚本。
    • 为了增加安全性,HTML5 引入了 sandbox 属性来限制 iframe 的行为。sandbox 限制了 iframe 中执行的操作,比如禁用表单提交、脚本执行等。
  4. SEO 问题:
    • 搜索引擎可能不会将 iframe 中的内容索引到搜索结果中。这是因为 iframe 是嵌套的,内容并不直接属于父页面,所以 iframe 中的内容对 SEO 的贡献较小。
总结:iframe 的使用建议
  • 何时使用iframe:
    • 当需要嵌入外部内容,特别是来自第三方站点的内容时,iframe 是最好的选择。它可以解决跨域和安全问题,并能提供更好的隔离性。
    • 在页面布局中,如果需要将某些内容与页面的其他部分隔离,或者使用独立的 JavaScript 框架时,iframe 也非常合适。
  • 何时避免使用iframe:
    • 如果是需要频繁交互的应用,或者需要高性能的页面,过多的 iframe 嵌套可能会导致性能下降。
    • 如果页面的 SEO 依赖于外部内容,嵌入的 iframe 内容可能不会被搜索引擎索引,因此应该谨慎使用。
  • 优化 iframe 的使用:
    • 避免嵌套过多的 iframe,确保 iframe 的内容尺寸与父页面响应式布局匹配。
    • 使用 sandbox 限制 iframe 内部的行为,增加安全性。
    • 使用 loading="lazy" 属性延迟 iframe 的加载,提升页面加载性能。

总体来说,iframe 在实现跨域内容和嵌入第三方资源方面非常有用,但应谨慎使用,以避免性能、SEO、安全等方面的问题。

CSS

浏览器绘制0.5px的方法与实现字体小于12px的解决方法,请列举多个方法

使用 CSS 的 transform 缩放

将1px进行缩放:

.line {
    width: 100%;
    height: 1px;
    background-color: #000;
    transform: scaleY(0.5);
    transform-origin: top;
}

将12px进行缩放:

.text {
    font-size: 12px;
    transform: scale(0.5);
    transform-origin: left top;
}
使用 border + transform

给元素的边框进行0.5缩放:

.line {
    border-top: 1px solid #000;
    transform: scaleY(0.5);
}
使用伪元素

通过伪元素设置1px的的高度并缩小:

.line {
    position: relative;
}
.line::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 1px;
    background-color: #000;
    transform: scaleY(0.5);
}

绘制三角形的方法有哪些?

常见的是使用border属性绘制一个三角形:

.triangle {
    width: 0;
    height: 0;
    border: 100px solid;
    border-color: red blue yellow green;
}

绘制结果

可以给宽度和高度都设置为0的元素,border的任何值都会直接相交,border其实就是用三角形创建的。

根据需要绘制的三角形方向,把其他朝向进行隐藏即可,如三角形朝下:

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

三角形朝下的效果

其他方法可以参考我引用的文章,介绍得很详细,但是不太常见,能简要阐述即可。

JavaScript

路由中history模式和hash模式各自的优劣和应用场景

Hash模式

定义:hash模式是一个把前端路由的路径有#号拼接在url后面的模式。当#后面路由发生变化,浏览器不会重新发起请求,而是触发onhashchange事件。

特点:

- hash可以改变url,但是不会触发页面重新加载,<font style="color:rgb(37, 41, 51);">即不会刷新页面。</font>
- <font style="color:rgb(37, 41, 51);">hash通过window.onhashchange的方式,来监听hash的改变,是按无刷新跳转。</font>
- <font style="color:rgb(37, 41, 51);">hash永远不会提交到server端。</font>
History模式

定义:history API是H5提供的新特性,允许开发者直接更改前端路由,即更新浏览器URL地址而不重新发起请求。

特点:

- 没有#号,路由地址看起更加整洁和美观。
- 通过pushState,replaceState来实现无刷新跳转的功能。
- nginx处需要配置相关的路由地址,不配置会出现找不到该页面的错误。
两者的应用场景
- toB的系统推荐使用hash模式,相对简单且容易,hash对url规范不敏感。
- toC的系统,可以考虑选择H5 history,需要服务端的支持与配置。

VUE

Vue3和Vue2之间的差异

  • 选项式API升级到组合式API
  • 性能改进:更快的虚拟DOM,tree-shaking更好地支持,更高效的响应式系统。
  • 响应式系统的升级,Vue2是Object.defineProperty而Vue3使用了Proxy来更好地实现响应式。
  • Vue3全面支持typeScript
  • 生命周期Vue3引入新的生命周期钩子配合组合式API函数来用语法更加简洁。
  • Fragment Vue3的template这次hi包括非单一容器
特性Vue2Vue3
API风格Options APIComposition API
响应式系统Object.defineProperty使用Proxy实现响应式
性能性能较低优化性能,虚拟DOM更高效
TypeScript支持支持较差完全用TypeScript编写
生命周期钩子常规钩子新增适配Composition API的钩子
多个根元素不支持支持Fragment
v-model只能绑定一个变量支持多个绑定,支持自定义事件名
Teleport不支持支持元素传送到DOM种其他位置
Suspense不支持支持一部组件加载时显示加载状态

Vue中使用for循环为什么key不能用index

当以数组为下标的index作为key值时,其中一个元素(例如增删改查)发生了变化就有可能导致所有的元素的key值发生改变,diff算法时比较同级之间的不同,以key来进行关联,当对数组进行下标的变换时,比如删除第一条数据,那么以后所有的index都会发生改变,那么key自然也跟着全部发生改变。

所以index作为key值是不稳定的,而这种不稳定性有可能导致性能的浪费,导致diff无法关联起上一次一样的数据。因此,能不使用index作为key就不使用index。

Vue.$nextTick()实现原理简述

  • Vue.nextTick 是通过微任务队列来实现的,它确保在 Vue 完成 DOM 更新后执行回调函数。
  • 它的实现依赖于浏览器环境,通常会使用 Promise.thenMutationObserver 来执行微任务,作为最后手段可以使用 setTimeout(宏任务)。
  • 你可以使用 nextTick 来确保在 DOM 更新后执行某些操作,特别是在处理动态内容、动画或依赖更新后的 DOM 的场景中。

原生js,vue,小程序获取url中的携带参数

获取 URL 中携带的参数在原生 JavaScript、Vue 和小程序中实现方法如下:

原生 JavaScript 获取 URL 参数

使用 URLSearchParams API 或正则解析。

使用 URLSearchParams
function getQueryParams(param) {
    const urlParams = new URLSearchParams(window.location.search);
    return urlParams.get(param); // 获取指定参数值
}

// 示例
console.log(getQueryParams("name")); // 假设 URL: ?name=John
使用正则解析
function getQueryParams(param) {
    const regex = new RegExp(`[?&]${param}=([^&#]*)`, "i");
    const match = window.location.search.match(regex);
    return match ? decodeURIComponent(match[1]) : null;
}

// 示例
console.log(getQueryParams("name")); // 假设 URL: ?name=John
Vue 中获取 URL 参数

Vue 是基于 JavaScript 的,可以直接使用前述的原生方法获取参数。也可以通过 Vue Router 提供的 $route 对象。

使用 Vue Router 获取参数
export default {
  mounted() {
    // 假设 URL: /example?name=DJ
    const name = this.$route.query.name; // 获取 query 参数
    console.log(name);
  }
};
不使用 Vue Router

直接使用原生方法,和第一部分类似:

mounted() {
  const urlParams = new URLSearchParams(window.location.search);
  const name = urlParams.get("name");
  console.log(name);
}
小程序中获取 URL 参数

小程序没有直接的 window.location,需要通过 onLoad 生命周期接收页面跳转时传递的参数。

Page({
  onLoad: function (options) {
    // options 对象包含页面跳转时传递的参数
    console.log(options.name); // 获取参数 name 的值
  }
});
总结
  • 原生 JS: 使用 URLSearchParams 或正则解析。
  • Vue: 推荐通过 $route.query 获取,简单直接。
  • 小程序: 在 onLoad 生命周期中通过 options 参数获取。

SPA第一次加载过慢如何解决

优化资源加载
  • 使用Webpack,Vite等工具进行代码拆分,按需加载。
  • 使用动态加载和懒加载。
const Component = () => import('./Component.vue');
  • 采用tree-shaking但是基本上打包工具默认开启
  • 在nginx端启用Gzip/Brotli压缩
gzip on; #开启压缩
gzip_http_version 1.1; #协议版本配置
gzip_comp_level 9; #压缩等级
gzip_types *;
优化图片和媒体
  • 延迟加载
  • 图片优化,使用工具压缩图片
减少JS的负担
  • 减少第三方库的依赖,避免过重依赖。
  • 从组件库按需引入组件
  • 缩小JS包,使用工具(如Webpack Bundle Analyzer)分析优化优化打包结果。
  • 打包时移除console.log语句。
提高缓存利用率
  • 使用强缓存和协商缓存,配置Cache-Control头部
location ~* \.(?:css|js|jpg|png|webp|svg)$ {
    expires 1y;
    cache-control: public;
}

设计模式

发布订阅模式

定义:引入中间媒介,订阅者可以订阅事件,发布者可以发布事件,事件中心负责通知订阅者。

核心思想:发布者和订阅者解耦,通过中间的消息系统进行通信。

典型应用:事件驱动,消息队列。

class EventBus{
  constructor(){
    this.event = {}; // 哈希表的思想
  }
  subscribe(event, callbaack){
    if(!this.events[event]){
      this.events[event] = [];
    }
    this.events[event].push(callback);
  }
  publish(event, data){
    if(this.events[event]){
      this.events[event].forEach(callback => callback(data));
    }
  }
}
const eventBus = new EventBus();

eventBus.subscribe('event1', data => console.log(`Subscriber 1 received: ${data}`));
eventBus.subscribe('event1', data => console.log(`Subscriber 2 received: ${data}`));

eventBus.publish('event1', 'Hello Subscribers!');

观察者模式

定义:被观察主体依赖多个关系,如一个对象的状态发生改变时,所有依赖它的对象都会发生变化。

核心思想:被观察者(Subject)直接通知观察者(Observer)。

典型应用:数据绑定,MVC模型

class Subject {
    constructor() {
        this.observers = [];
    }
    addObserver(observer) {
        this.observers.push(observer);
    }
    notifyObservers(message) {
        this.observers.forEach(observer => observer.update(message));
    }
}

class Observer {
    update(message) {
        console.log(`Observer received: ${message}`);
    }
}

// 使用
const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notifyObservers('Hello Observers!');

对比图

因两者比较相似,以下进行比较

特性观察者模式发布-订阅模式
参与者被观察者、观察者发布者、订阅者、事件中心
通信方式被观察者直接通知观察者发布者通过事件中心通知订阅者
耦合性耦合度较高解耦性更强
通知范围通知的范围较固定,直接绑定关系通知的范围较广,通过事件中心动态管理
应用场景数据绑定、依赖更新事件驱动、跨模块通信

总结

以上,可以看出前端的面试题涉及的范围还是挺广的,不仅仅涉及到前端基础三件套,还涉及到打包部署和设计模式相关领域,所以还是得从日常工作抓起,养成及时记录问题,整理复盘的习惯,不要寄希望于临时抱佛脚,祝准备金三银四跳槽的各位顺利~

参考文章: