简历可能问到的问题

223 阅读11分钟

vue复习

www.yuque.com/12312wo/keb…

vue2和vue3的diff算法的区别?

vue2和vue3的区别?

www.bilibili.com/video/BV1AY…

webpack

为什么要有webpack?

image.png

juejin.cn/post/728086…

热更新的原理

待补充

js运行机制

  1. 什么是同步什么是异步

image.png 2. js是单线程的 image.png 3. 事件循环

image.png

  1. 宏任务、微任务

image.png await后面的代码相当于.then。

性能优化

性能指标:

image.png

检测网站性能:灯塔

image.png

image.png

前端安全

image.png image.png

image.png

image.png

重构

image.png

image.png

预渲染

image.png

image.png

image.png

eslint规范

  1. 安装 ESLint:npm install eslint --save-dev
  2. 初始化配置文件:在项目根目录下执行 eslint --init 命令,按照提示选择相应的配置选项。这将生成一个 .eslintrc.eslintrc.js 配置文件。
  3. 配置规则:打开生成的 .eslintrc.eslintrc.js 文件,可以根据项目需求和团队约定修改或添加规则。可以在配置文件中的 rules 属性中设置具体的规则,也可以使用 extends 属性引入其他规则配置,例如 "extends": "eslint:recommended"
  4. 配置忽略文件:在配置文件中可以使用 ignorePatterns 属性指定需要忽略的文件或目录,例如 "ignorePatterns": ["dist/", "node_modules/"]
  5. 添加命令脚本:在 package.json 文件的 scripts 属性中添加一个脚本,用于运行 ESLint 检查代码。例如:
"scripts": {
  "lint": "eslint . --ext .js"
}

这里的脚本命令是运行 eslint 命令来检查当前目录下所有后缀为 .js 的文件。

  1. 运行 ESLint:使用命令 npm run lintyarn lint 来运行 ESLint 检查代码。如果有不符合规则的地方,会在终端中显示错误或警告信息,并指导如何修复问题。

commit规范

利用husky+commitlint来做提交前的校验

image.png

image.png

封装组件

数据灵活 结构灵活 事件灵活

图片压缩

www.yuque.com/12312wo/hrp…

白屏问题

产生的原因:

网络问题:网络延迟或者网络不稳定可能导致资源加载缓慢或失败,从而引起白屏。

资源加载问题:如果页面引入的css或js文件、图片等资源存在404或者其他加载问题,也会导致白屏问题。

js错误:如果页面的js代码出现了错误,可能会导致页面无法正常渲染。

DOM结构错误:如果页面中的HTML代码存在语法错误,可能会导致浏览器无法正确解析DOM结构。 渲染性能问题:如果页面中存在大量复杂的DOM结构或者渲染性能问题,也可能导致白屏问题。

解决

image.png

规范

image.png

大文件上传

  1. 先获取文件:打印出来是个文件对象

image.png

  1. 对file文件进行切片:file中有slice方法,打印出来piece是blob类型,blob类型可以直接发送给服务器

image.png 3. 写一个切片函数,传递文件,传递切片大小,就可以帮助完成切片。(将切片结果放在result数组中进行保存)

image.png 4. 特殊场景:假设传到某个切片的时候断网了,下次还需要接着上传,还怎么继续传。

通过一次ajax请求就知道要传递哪些范围的分片 image.png

那客户端怎么告诉服务端这个文件呢???(我们需要找到唯一的东西代表这个文件,就是文件hash)

hash算法有很多,我们用的是md5. 接下来我们如何计算这个文件的hash值是什么???所以我们需要使用第三方库spark-md5算出文件的hash值。

  1. 计算文件hash值(分块去算hash值,叫增量算法)

image.png

垃圾回收机制

引用计数法:

image.png 问题: 循环引用,引用次数不可能为0,无法回收,内存无法释放。

标记清除法:

image.png 从根对象开始遍历,将存活的对象标记为1,如下图:

image.png

image.png 最后将所有标记为1的对象,标记为0,方便下一次垃圾回收机制回收,如下图:

image.png

问题: 位置是不连续的

image.png

image.png

V8对垃圾回收机制的优化

image.png 新生代:

form空间是使用空间,to是闲置空间,当form空间中的对象要满的时候,我们就开始标记,将存活的对象标记好,标记好后,将他们复制到闲置空间中,然后把form空间清空,再交换to、form名称。

老生代:

首先将所有对象标记为0,将存活对象标记为1,将标记为0的对象清空,将标记为1的对象标记为0,最后再用标记压缩算法,使他们的位置整理好。

问题:js是单线程的,所以垃圾回收机制会阻塞js执行,V8机制对这种情况做了优化,垃圾回收机制支持多线程并行回收。但是这样依旧会阻塞js的执行,所以诞生了增量标记,增量标记最大的特点是:垃圾回收可以分段执行。

image.png

那如何记录上一次回收的位置呢?

image.png

将上次标记的位置标记为灰色,当下次执行的时候,从灰色开始重新标记,V8还支持并行回收。

内存泄漏

www.bilibili.com/video/BV1Ro…

下划线转成驼峰

function toHump(name) {
    return name.replace(/_(\w)/g, function(all, letter){
        return letter.toUpperCase();
    });
}
toHump('hello_js_go') //helloJsGo

驼峰转成下划线

function toLine(name) {
  return name.replace(/([A-Z])/g,"_$1").toLowerCase();
}
toLine('aBcdEfg') //a_bcd_efg

实现Event-bus

class EventBus {
  constructor() {
    this.events = {};
  }

  // 订阅事件
  on(eventName, callback) {
    if (!this.events[eventName]) {
      this.events[eventName] = [];
    }
    this.events[eventName].push(callback);
  }

  // 发布事件
  emit(eventName, data) {
    const eventCallbacks = this.events[eventName];
    if (eventCallbacks) {
      eventCallbacks.forEach((callback) => {
        callback(data);
      });
    }
  }

  // 取消订阅事件
  off(eventName, callback) {
    const eventCallbacks = this.events[eventName];
    if (eventCallbacks) {
      this.events[eventName] = eventCallbacks.filter((cb) => cb !== callback);
    }
  }
}

// 创建一个全局的 Event-bus 实例
const eventBus = new EventBus();

// 示例用法
// 订阅事件
eventBus.on('event1', (data) => {
  console.log('Event 1:', data);
});

// 发布事件
eventBus.emit('event1', 'Hello, World!');

// 取消订阅事件
const callback = (data) => {
  console.log('Event 2:', data);
};
eventBus.on('event2', callback);
eventBus.emit('event2', 'Goodbye!');
eventBus.off('event2', callback);


在上述示例中,EventBus 类表示一个 Event-bus 对象,它具有 onemitoff 方法。

  • on(eventName, callback):用于订阅事件。将事件名称 eventName 和回调函数 callback 添加到事件列表中。
  • emit(eventName, data):用于发布事件。触发事件名称为 eventName 的事件,并将数据 data 传递给订阅该事件的回调函数。
  • off(eventName, callback):用于取消订阅事件。从事件列表中移除事件名称为 eventName,且回调函数为 callback 的订阅。

通过创建一个全局的 Event-bus 实例,不同组件可以订阅、发布和取消订阅事件,实现它们之间的通信。当某个组件调用 emit 方法发布事件时,所有订阅该事件的回调函数都会被触发执行,并且可以传递数据作为参数。

需要注意的是,上述示例的 Event-bus 实现比较简单,没有考虑多个实例、异步操作、错误处理等情况。在实际应用中,可能需要根据具体需求进行功能扩展和优化。

Event-bus 如何改造成 Promise 的接口

Event-bus 是一种常见的前端开发模式,用于实现组件间通信,但是通过 Promise 更加符合现代 JavaScript 开发思路。下面简单介绍一下如何将 Event-bus 改造为 Promise 的接口。

  1. 创建一个 Promise 对象:在 Event-bus 中发送事件时,我们可以将其封装为一个 Promise 对象。例如,我们可以定义一个函数 emitPromise,它接收相应的参数,返回一个 Promise 对象。
function emitPromise(event, ...params) {
    return new Promise((resovle, reject) => {
        eventBus.$emit(event, ...params);
        resolve();
    })
}

其中,event 参数表示要发送的事件名称,params 参数表示要传递给事件监听器的参数。我们通过调用 $emit 方法来触发事件,并在 Promise 的 resolve 方法中返回结果。

  1. 监听 Promise 对象:在 Event-bus 中监听事件时,我们可以根据事件名称注册一个回调函数。对于 Promise 对象,我们可以使用 .then() 方法来监听事件完成的状态。
function onPromise(event) {
  return new Promise((resolve, reject) => {
    eventBus.$on(event, (result) => {
      resolve(result);
    });
  });
}

其中,event 参数表示要监听的事件名称。我们先创建了一个 Promise 对象,并在 $on 方法中注册了一个回调函数,当事件触发时,回调函数会将结果传递给 Promise 的 resolve 方法。

  1. 使用 Promise 接口:在 Event-bus 中,我们可以使用 $emit 方法来发送事件,使用 $on 方法来监听事件。在使用 Promise 接口时,我们可以将其改为使用 emitPromise 函数来发送事件,使用 onPromise 函数来监听事件。
// 发送事件
emitPromise('event-name', 'param1', 'param2')
  .then(() => {
    console.log('事件触发成功!');
  });

// 监听事件
onPromise('event-name')
  .then((result) => {
    console.log(`事件接收到了结果:${result}`);
  });

上述代码中,我们使用 emitPromise 函数发送了一个名为 event-name 的事件,并传递了两个参数。在 .then() 方法中,我们定义了事件触发成功后的回调函数。

同时,我们使用 onPromise 函数监听了同样的事件名称。在 .then() 方法中,我们定义了接收完成后的回调函数,它会接收到事件传递的结果。

通过这种方式,我们可以使用 Promise 更加优雅地实现组件间通信,并且能够使用 Promise 接口提供的丰富功能,例如链式调用、错误处理等。

npm版本号比较大小

版本号比较的原则如下:

  1. 首先比较主版本号(MAJOR),如果有差异,则选择较大的版本。
  2. 如果主版本号相同,再比较次版本号(MINOR),如果有差异,则选择较大的版本。
  3. 如果主版本号和次版本号都相同,再比较修订版本号(PATCH),如果有差异,则选择较大的版本。

在比较版本号时,可以使用 npm semver 模块提供的 gtltgtelte 等函数。这些函数用于比较两个版本号的大小。

以下是使用 npm semver 模块进行版本号比较的示例代码:

javascriptCopy Code
const semver = require('semver');

const version1 = '1.2.3';
const version2 = '1.3.0';

if (semver.gt(version1, version2)) {
  console.log(`${version1} is greater than ${version2}`);
} else if (semver.lt(version1, version2)) {
  console.log(`${version1} is less than ${version2}`);
} else {
  console.log(`${version1} is equal to ${version2}`);
}

在上述示例中,我们通过 semver.gt 函数比较了 version1version2 的大小。如果 version1 大于 version2,则打印出 ${version1} is greater than ${version2};如果 version1 小于 version2,则打印出 ${version1} is less than ${version2};如果两个版本号相等,则打印出 ${version1} is equal to ${version2}

通过使用 npm semver 模块,可以方便地进行版本号的比较和判断。

如果一个用户在北京的特定机型上出现了白屏问题,而周围的同事使用相同的机型没有复现该问题,那么可能是由于一些特定的环境或配置导致的。以下是一些排查思路:

  1. 浏览器版本:首先确认用户使用的是哪个浏览器版本,是否与其他同事使用的浏览器版本有差异。如果有差异,可以尝试升级或降级浏览器版本,看是否能够复现问题。
  2. 缓存问题:如果用户之前访问过该页面,可能存在缓存导致页面无法正常加载。可以尝试清除浏览器缓存,或者在代码中添加版本号来强制刷新页面。
  3. 网络问题:确认用户的网络状况是否正常,尝试使用相同的网络环境测试页面是否能正常加载。如果网络不稳定,可能会导致页面加载失败或延迟。
  4. 设备配置:检查用户的设备配置,例如屏幕分辨率、操作系统版本等,是否与其他同事有差异。这些差异可能影响页面的布局和渲染。
  5. 兼容性问题:确保所使用的前端框架、库和特性支持用户的设备和浏览器。在某些情况下,特定的前端特性可能在某些浏览器或设备上不被支持,需要进行相应的兼容性处理。
  6. 错误日志:检查是否有错误日志记录。在前端代码中添加错误捕获和日志记录的功能,可以帮助快速定位问题所在。
  7. 与用户沟通:与用户详细沟通,了解具体操作步骤、输入内容等。可能用户在特定的操作步骤下才会出现白屏问题,从而帮助定位到问题所在。

综上所述,针对该白屏问题,可以从浏览器版本、缓存、网络、设备配置、兼容性、错误日志和与用户的沟通等多个角度来排查问题,并根据具体情况逐步缩小问题范围,最终找到导致白屏问题的原因并进行修复。

localstorage 大家都去写, 很容易就写满了. 如何处理呢?

以下是一些处理 LocalStorage 容量限制的方法:

  1. 使用 SessionStorage:与 LocalStorage 类似,SessionStorage 也是一种本地存储机制,但是它存储的数据只在当前会话期间有效,即当用户关闭浏览器标签页或窗口后,SessionStorage 中的数据将被删除。因此,如果你只需要在会话期间保存少量的数据,可以考虑使用 SessionStorage。

  2. 压缩数据:如果你需要存储较大的数据,可以尝试对数据进行压缩,以减小存储空间的占用。可以使用一些 JavaScript 库,如 pako.js、lz-string.js 等来处理压缩和解压缩操作。

  3. 删除过期数据:如果你的应用需要定期清理 LocalStorage 中的过期数据,可以在存储每个值的同时存储一个时间戳,以便在需要时检查该值是否过期,并定期清理已过期的数据。

  4. 拆分数据:如果你需要存储大量的数据,可以考虑将数据拆分为更小的部分,然后在需要时合并成一个完整的数据。这样可以降低每个键值对所占用的存储空间,同时也方便了数据的管理。

  5. 使用 IndexedDB:IndexedDB 是一种比 LocalStorage 更强大的浏览器内存储机制,它使用类似数据库的方式来存储数据,并支持事务操作、复杂查询等功能。如果你需要存储海量数据并进行高效的读写操作,可以考虑使用 IndexedDB。

  6. 使用 try-catch 捕获异常:当写入 LocalStorage 的时候,可以使用 try-catch 块来捕获写入过程中可能出现的异常,在捕获到异常后进行相应的处理,例如清空 LocalStorage,或者向用户提示存储空间已满的消息。

javascriptCopy Code
try {
  localStorage.setItem(key, value);
} catch (e) {
  // 处理异常,例如清空 LocalStorage
  localStorage.clear();
  // 或者提示用户存储空间已满
  alert('LocalStorage已满,请清理存储空间');
}
  1. 使用存储队列:将需要存储的数据放入一个队列中,然后通过定时器或者其他方式依次从队列中取出数据,写入 LocalStorage。这样可以保证每次写入的数据量不会过大,从而避免 LocalStorage 容量满的问题。
javascriptCopy Code
let storageQueue = []; // 存储队列

function addToStorageQueue(data) {
  storageQueue.push(data);
}

function writeToLocalStorage() {
  if (storageQueue.length > 0) {
    const data = storageQueue.shift();
    try {
      localStorage.setItem(data.key, data.value);
    } catch (e) {
      // 处理异常,例如清空 LocalStorage
      localStorage.clear();
      // 或者提示用户存储空间已满
      alert('LocalStorage已满,请清理存储空间');
    }
  }
}

// 定时器每隔一段时间写入一次 LocalStorage
setInterval(writeToLocalStorage, 1000);

原型

对象获取原型: image.png

image.png

构造函数获取原型:

image.png

原型对象类与继承

image.png

image.png

继承:

image.png

image.png

原型对象的继承:

image.png

image.png

原型链上的最终指向为object

image.png

instanceof原理

image.png image.png

箭头函数和普通函数的区别

深度克隆

image.png

为什么需要虚拟DOM

1. 框架设计

数据驱动:数据一变化,在render函数中就要全量生成,由于他是这样子设计的,就导致了如果这里面有真实DOM存在,就要操作真实的DOM,真实DOM很昂贵,就会严重的影响效率。没办法使用了虚拟DOM,比较虚拟DOM哪个变了,再去操作真实的DOM

跨平台:浏览器环境才认识真实DOM,一旦脱离了浏览器环境,就不行了。因此搞了有个所有环境都认识的虚拟DOM。根据不同的环境,使用虚拟DOM渲染出界面,就可以实现一套代码多端使用了。