# interview **Repository Path**: ifercarly/interview ## Basic Information - **Project Name**: interview - **Description**: 面试题目进阶 - **Primary Language**: Unknown - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 43 - **Forks**: 9 - **Created**: 2021-09-04 - **Last Updated**: 2025-06-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: 面试 ## README ## 00. [BFC](./resource/00/README.md)​ ✔ ## 01. [HTTP Cache](./resource/01/README.md) ✔ ## 02. [new](./resource/02/README.md) ✔ ## 03. [instanceof](./resource/03/README.md) ✔ ## 04. [DeepClone](./resource/04/README.md) ✔ ## 05. [~~发布订阅和观察者~~](./resource/05/README.md) ✔ ## 06. [Vue 双向数据绑定](./resource/06/README.md) ✔ ## 07. [敲回车后发生了甚么事情](./resource/07/README.md) ✔ ## 08. [写个 Promise](./resource/08/README.md) ## 09. [洋葱模型](./resource/09/README.md) ✔ ## 10. [Node 事件循环](./resource/10/README.md) ## 11. [数组去重](./resource/11/README.md) ✔ ## 12. [React Fiber](./resource/12/README.md) ## 13. [React setState](./resource/13/README.md) ## 14. [Vue nextTick](./resource/14/README.md) ## 15. [DOM Diff](./resource/15/README.md) ## 16. [Webpack 优化](./resource/16/README.md) ## 17. [Type 和 Interface](./resource/17/README.md) ## 18. [关于 HTTPS](./resource/18/README.md) ✔ ## 19. [Node Stream](./resource/19/README.md) ✔ ## 20. [关于 Vue3](./resource/20/README.md) ## 21. [history 路由模式上线时后端做什么](./resource/21/README.md) ## 22. [柯里化](./resource/22/README.md) ✔〽 ## 23. [Async 和 Defer](./resource/23/README.md) ✔ ## 24. [Vuex 原理](./resource/24/README.md) ## 25. [设计模式](./resource/25/README.md) ## 26. [RBAC](./resource/26/README.md) ✔ ## 27. [常见排序算法](./resource/27/README.md) 〽 ## 28. [v-for 和 v-if 为什么不能一起用](./resource/28/README.md) ## 29. [拍平数组](./resource/29/README.md) ## 30. [Array to tree](./resource/30/README.md) ## 31. [Vue 父子生命周期](./resource/31/README.md) ## 32. [Polyfill call、apply、bind](./resource/32/README.md) ✔ ## 33. [Map、Set、WeakMap、WeakSet](./resource/33/README.md) ## 34. [Class 中的箭头函数和其中的 this](./resource/34/README.md) ## 35. [Debounce / throttle](./resource/35/README.md) ✔ ## 36. [HTTP2](./resource/36/README.md) ✔ ## 37. [Promise.all](./resource/37/README.md) ## 38. [Why vue3 uses proxy instead](./resource/38/README.md) ## 39. [骨架屏原理](./resource/39/README.md) ## 40. [小程序支付](./resource/40/README.md) ## 41. [ES 新特性](./resource/41/README.md) ## 42. [JS Extends](./resource/42/README.md) ## 43. [RequestAnimationFrame](./resource/43/README.md) ## 44. [Redraw & reflow](./resource/44/README.md) ✔ ## 45. [flex 是哪几个属性的简写](./resource/45/README.md) ## 46. [Vue Router 钩子](./resource/46/README.md) ## 47. [for/in & for/of](./resource/47/README.md) ✔ ## 48. [MutationObserver](./resource/48/README.md) ## 49. [Vue.extend](./resource/49/README.md) ## 50. [代码规定](./resource/50/README.md) ## 51. [路由传参](./resource/51/README.md) ## 52. [头条项目优化](./resource/52/README.md) ## 53. [Event Loop](./resource/53/README.md) ✔ ## 54. [长列表优化](./resource/54/README.md) ## 55. [Generator](./resource/55/README.md) ## 56. [Padding 实现图片的自适应](./resource/56/README.md) ## 57. [数据结构和算法](./resource/57/README.md) ## 58. [SASS 语法进阶](./resource/58/README.md) ## 59. [Vue SSR 基础](./resource/59/README.md) ## 60. [Vue SSR 案例](./resource/60/README.md) ## 61. [Mock.js](./resource/61/README.md) ## 62. [界面访问控制](./resource/62/README.md) ## 63. [BEM](./resource/63/README.md) ## 64. [原子化 CSS](./resource/64/README.md) ## 65. [React SSR](./resource/65/README.md) ## 66. [中台是啥](./resource/66/README.md) ## 67. [TypeScript](./resource/67/README.md) ```bash Todo: Vue React 八股 flex Node EventLoop 数据结构和算法 ``` ## 68. [BFF](./resource/68/README.md) ## 69. RxJS ## 70. 微前端 ## 71. CI/CD ## 72. Docker ## 73. 大数问题 ## 74. 位运算 ## 75. Webpack 生命周期 ## 76. Axios 跨域原理 ## 77. 错误捕获和监控 ## 78. 一次性把大量元素插入到页面 ## 79. 闭包应用场景(什么时候释放) ## 80. 移动端一屏页面展示 ## 81. [git merge 和 git rebease](./resource/81/README.md) ## 82. [为什么要对 URL 中的参数进行编码](./resource/82/README.md) ## 83. will-change ## 84. flutter ## 85. loader 和 plugin ## 86. 白屏 ## 87. BeforeDestroy 可以操作 DOM 吗 ## 88. import 和 require 的区别 ## 89. Webpack Plugin 生命周期 ## 90. transform 和 fixed 相互影响的问题 ## 91. [qiankun](https://qiankun.umijs.org/zh/)、[G6](http://antv-2018.alipay.com/zh-cn/g6/3.x/demo/index.html)、[X6](https://x6.antv.vision/zh/docs/tutorial/about)、[Jest](https://www.jestjs.cn/) ## 92. Performance ## 93. Bundle 和 Chunk ## 94. Web Workers ## 95. WebSocket 心跳机制 ## 96. 动态表单 ## 97. [OpenId 和 uid](https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html) ## 98. [移动端网页如何分享到微信](./resource/98/README.md) ## 99. [第三方登录](./resource/99/README.md) ## 100. [网页支付宝支付](./resource/100/README.md) ## 101. 生成 1 ~ 100 ```js ;[...Array(100).keys()] ``` ## 102. 转发,移动端网页如何分享到微信? [官网](https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html) \1. 绑定域名到微信公众号的后台。 \2. 引入微信官网提供的 JS 文件。 \3. 通过 `wx.config` 接口注入权限验证配置。 ```js wx.config({ debug: true, // 开启调试模式,调用的所有 api 的返回值会在客户端 alert 出来,若要查看传入的参数,可以在 pc 端打开,参数信息会通过 log 打出,仅在 pc 端时才会打印。 appId: '', // 必填,公众号的唯一标识 timestamp: , // 必填,生成签名的时间戳 nonceStr: '', // 必填,生成签名的随机串 signature: '',// 必填,签名 jsApiList: [] // 必填,需要使用的 JS 接口列表 }); ``` \4. 调用微信提供的相关分享接口。 ```js wx.ready(function () { //需在用户可能点击分享按钮前就先调用 wx.updateAppMessageShareData({ title: '', // 分享标题 desc: '', // 分享描述 link: '', // 分享链接,该链接域名或路径必须与当前页面对应的公众号 JS 安全域名一致 imgUrl: '', // 分享图标 success: function () { // 设置成功 }, }) }) ``` ## 103. 撤销 ## 104. 低代码实现思路 ## 105. flex 骰子 ## 106. Canvas 水印 ## 107. 不用循环生成序号 ```js Array.from(Array(11), (_, index) => index + 1) [...Array(11).keys()].map((_, index) => index + 1) ``` ## 108. 写一个 Pick ## 109. 前端安全 ## 110. rebase 场景 1:让提交记录变得简洁。 ```bash git rebase -i 版本号 # 会合并指定版本号之后的所有 commit 记录 git rebase -i HEAD~3 # 从当前开始合并最近的三条记录 ``` 场景 2:合并分支。 ```bash // # 使用方式 1 git checkout dev git rebase master git checkout master git merge dev // # 使用方式 2 git checkout master git rebase dev ``` 就是历史时间线的区别,merge 保留了你所有的操作记录,而 rebase 把提交的节点变成了线性的时间线,如果分支 merge 很多的话,时间线会错综复杂,这个时候 rebase 的好处就出现了,对人肉追溯比较友好。 git rebase 发生了甚么事情? ## 111. axios 关闭请求 ## 112. 组织架构数据很多 ## 113. 远程组件 ## 114. 权限是怎么做的 ## 115. ES Modules 的静态引入 就是通过限定语法,让本来需要运行代码才能确定的依赖,可以在分析 AST 阶段就确定下来。 ## 116. 两数之和 ```js /* const twoSum = function (arr, target) { const obj = {} for (let i = 0; i < arr.length; i++) { if (arr[i] in obj) { return [obj[arr[i]], i] } else { obj[target - arr[i]] = i } } } */ const twoSum = (arr, target) => { for (let i = 0; i < arr.length; i++) { for (let j = 0; j < arr.length; j++) { if (arr[i] + arr[j] === target && i !== j) { return [i, j] } } } } const arr = [1, 2, 5, 9] console.log(twoSum(arr, 10)) ``` ## 117. TS 获取对象的 key ```js const o = { name: 'ifer', age: 18 } Object.keys(o).forEach(item => { console.log(o[item as keyof typeof o]) }) ``` ## 118. Promise ```js new Promise((resolve, reject) => { setTimeout(() => { resolve(233) }) }) class Promise { constructor(executor) { this.status = 'pending' // Promise 的初始状态为 pending this.value = null // Promise 的结果值 this.callbacks = [] // Promise 的回调函数数组 // executor 是一个带有 resolve 和 reject 参数的函数 // resolve 函数用于将 Promise 状态设置为 fulfilled,同时将结果值存储在 value 变量中 // reject 函数用于将 Promise 状态设置为 rejected,同时将错误原因存储在 value 变量中 try { // 给 executor 函数传递 2 个实参,这两个实参也都是函数类型 executor(this.resolve.bind(this), this.reject.bind(this)) } catch (error) { this.reject(error) } } resolve(value) { if (this.status === 'pending') { this.status = 'fulfilled' this.value = value this.callbacks.forEach((callback) => callback.onFulfilled(value)) } } reject(reason) { if (this.status === 'pending') { this.status = 'rejected' this.value = reason this.callbacks.forEach((callback) => callback.onRejected(reason)) } } then(onFulfilled, onRejected) { if (typeof onFulfilled !== 'function') { onFulfilled = (value) => value } if (typeof onRejected !== 'function') { onRejected = (reason) => { throw reason } } const promise = new Promise((resolve, reject) => { if (this.status === 'fulfilled') { setTimeout(() => { try { const result = onFulfilled(this.value) this.handleResult(result, resolve, reject) } catch (error) { reject(error) } }) } else if (this.status === 'rejected') { setTimeout(() => { try { const result = onRejected(this.value) this.handleResult(result, resolve, reject) } catch (error) { reject(error) } }) } else { this.callbacks.push({ onFulfilled: (value) => { try { const result = onFulfilled(value) this.handleResult(result, resolve, reject) } catch (error) { reject(error) } }, onRejected: (reason) => { try { const result = onRejected(reason) this.handleResult(result, resolve, reject) } catch (error) { reject(error) } }, }) } }) return promise } catch(onRejected) { return this.then(null, onRejected) } handleResult(result, resolve, reject) { if (result instanceof Promise) { result.then(resolve, reject) } else { resolve(result) } } static resolve(value) { return new Promise((resolve) => resolve(value)) } static reject(reason) { return new Promise((_, reject) => reject(reason)) } static all(promises) { const results = new Array(promises.length) let count = 0 return new Promise((resolve, reject) => { promises.forEach((promise, index) => { Promise.resolve(promise).then((value) => { results[index] = value count++ if (count === promises.length) { resolve(results) } }, reject) }) }) } } ``` ## 119. 去重 ```js const arr = [ { name: "xiaoming", age: 19 }, { name: "xiaoming", age: 20 }, { name: "xiaoming", age: 18 }, { name: "xiaohong", age: 30 } ] ``` ```js const result = Object.values(arr.reduce((acc, cur) => { if (!acc[cur.name] || acc[cur.name].age < cur.age) { acc[cur.name] = cur; } return acc; }, {})); ``` ## 120. [组件二次封装](./resource/120/README.md) 优先 CSS;回归操作 DOM,自由自在。 ```html ``` ## 121. 文件上传 无标题-2023-05-15-1052 多文件上传的两层含义:一个一个选择,循环单文件,调用单文件上传的接口到后端;直接选择多文件。 切片上传。 ```js function upload(blobOrFile) { const xhr = new XMLHttpRequest(); xhr.open('POST', '/server', true); xhr.onload = function(e) { ... }; xhr.send(blobOrFile); } document.querySelector('input[type="file"]').addEventListener('change', function(e) { let blob = this.files[0]; const BYTES_PER_CHUNK = 1024 * 1024; // 1MB chunk sizes. const TOTAL = blob.size; let start = 0; // 这个 end 表示 slice 的截取结束位置 let end = BYTES_PER_CHUNK; while(start < TOTAL) { upload(blob.slice(start, end)); start = end; end = start + BYTES_PER_CHUNK; } }, false); ``` ### Blob 属性、截取方法、转换方法。 ```js const blob = new Blob(["Hello, world!"], { type: "text/plain" }); // #1 属性 console.log(blob.size); // 13 byte console.log(blob.type); // #2 截取方法 const partialBlob = blob.slice(0, 5); console.log(partialBlob); // 返回一个新的 blob 对象 // #3 转换方法(这儿也可以借助 FileReader 进行转换) // text(),该方法将 Blob 的内容读取为文本字符串,它返回一个 Promise,解析为文本数据。 partialBlob.text().then(console.log); // Hello // arrayBuffer(),该方法将 Blob 的内容读取为 ArrayBuffer 对象,适合处理二进制数据,它返回一个 Promise,解析为 ArrayBuffer 数据。 partialBlob.arrayBuffer().then(console.log); // stream(),该方法将 Blob 的数据作为一个 ReadableStream 返回,允许你以流的方式处理数据,适合处理大文件。 ``` 应用场景。 ```js // 下载 const url = URL.createObjectURL(blob); // 创建一个 Blob URL const a = document.createElement("a"); a.href = url; a.download = "test.txt"; a.click(); URL.revokeObjectURL(url); // 释放 URL 对象 ``` ```js // 上传 // 你可以通过 FormData 对象将 Blob 作为文件上传到服务器 const formData = new FormData(); formData.append("file", blob, "example.txt"); fetch("/upload", { method: "POST", body: formData, }).then((response) => { console.log("File uploaded successfully"); }); ``` ### File File => Base64 ```js // 读取 File 对象为图片 oFile.onchange = function (e) { console.log(e.target.files[0]); }; // 通过 FileReader 的 readAsDataURL 方法读取 File 为 base64 ``` 可以使用 Input File 框的方式来得到 File,我们也可以手动创建 File 对象: ```js const file = new File(["Hello, world!"], "hello-world.txt", { type: "text/plain", }); ``` File 是 Blob 的子类,File 对象除了具有 Blob 的所有属性和方法之外,还包含文件的元数据,如文件名和修改日期,你可以将 File 对象看作是带有文件信息的 Blob。 ## 122. 文件下载 1\. `window.open()`,无法命名,当后端以 GET 的方式返回 blob 的数据可使用。 2\. 利用 a 标签的 download 属性。 ```js axios.get('http://xxx', { responseType: 'blob' }, function() { if (window.navigator.msSaveBlob) { } else { // #1 创建 blobURL const blobURL = URL.createObjectURL(后端返回的文件信息) // #2 创建 a 标签 const a = document.createElement('a') // #3 把 blobURL 给 a 标签的 href 属性 a.href = blobURL // #4 给标签设置 download 属性 a.download = 'xxx.ppt' // #5 隐藏 a 标签 a.style.display = 'none' // #6 主动触发 a 标签的点击 a.click() // #7 释放内存中的 blobURL URL.revokeObjectURL(blobURL) } }) ``` 3\. [file-saver](https://www.npmjs.com/package/file-saver) ## 123. Excel / Word | | 通用 | Vue | React | | -------- | ---- | ---------------------------- | ----------------- | | 解析内容 | xlsx | xlsx | xlsx | | 预览内容 | xlsx | @vue-office/excel、docx、pdf | react-file-viewer | Blob => ArrayBuffer => Read 方法读为 book 对象 => 提取出对应 sheet 对象 => 输出为 HTML/JS 等;创建 workbook,输出 excel。 1\. 把 DOM 结构转成 Excel 对象。 ```js import { writeFile } from 'xlsx' htmlToSheet() { // const tableDOM = this.$refs.tableDOM.$el.querySelector('table') const tableDOM = this.$refs.tableDOM const ws = utils.table_to_sheet(tableDOM) const wb = utils.book_new() utils.book_append_sheet(wb, ws, 'sheet1') writeFile(wb, 'xxx.xlsx') } ``` 2\. 把 JS 对象转为 Excel 对象。 ```js dataToSheet() { // workSheet const ws = utils.json_to_sheet(this.tableData) // workbook const wb = utils.book_new() utils.book_append_sheet(wb, ws, 'sheet1') writeFile(wb, 'xxx.xlsx') } ``` 1\. 本地选择读取为 HTML 或 JS 对象。 ```ts uploadFile(e) { const _file = e.target.files[0] _file.arrayBuffer().then(r => { // workbook const wb = read(r) // 取表一 const sheet1 = wb.Sheets.Sheet1 // console.log(utils.sheet_to_json(sheet1)) this.html = utils.sheet_to_html(sheet1) // utils.sheet_to_csv(sheet1) }) } ``` 2\. 请求接口读取为 HTML 或 JS 对象。 ```js axios.get('https://xxx', { responseType: 'blob' }).then(res => { res.data.arrayBuffer().then(res => { // ... }) }) ``` `预览` ```html ``` `word` | | 通用 | Vue | React | | ------------ | ---------------------- | ---------------- | ----------------- | | 解析内容操作 | docxtemplater | docxtemplater | docxtemplater | | 预览内容操作 | mammoth / docx-preview | @vue-office/docx | react-file-viewer | ## 124. bignumber.js ```js const a = new BigNumber(0.1) const b = new BigNumber(0.2) const c = new BigNumber(0.3) // console.log(a.toString()) // console.log(a.toNumber()) console.log(a.plus(b).toNumber()) // 0.3 console.log(c.minus(a).toNumber()) // 0.2 ``` ## 125. canvas 压缩图片。 ```html Document ``` 页面截图,如果是 DOM 的话可以借助 `html2canvas` 这个库,图片其实不需要,直接划上去下载就行了。 ```html ``` 添加滤镜,`可以使用第三方的滤镜算法`。 ```html Document
``` 图片裁剪。 ```html Document ``` ## 126. indexedDB ## 127. [并发请求封装](./resource/127/README.md) ## 128. 动态表单 `App.vue` ```html ``` `components/TestForm.vue` ```html ``` ## 129. 切片 长时间运行的 JS 会阻塞,阻碍渲染,可以切片后渲染。 requestAnimation 定义的任务,会在浏览器渲染完成后去执行。 所以我们只需要把每个切片放到 requestAnimation 中,他在执行完一个后,会等着浏览器渲染完成再执行下一个。 `App.vue` ```html ``` ## 130. Webpack 优化 1\. 不要让 loader 做太多事情,`include` 和 `exclude`。 2\. 开启缓存将转译结果缓存至文件系统。 ```js loader: 'babel-loader?cacheDirectory=true' ``` 3\. 第三方库制作动态链接库,这个依赖库不会跟着你的业务代码一起被重新打包,只有当依赖自身发生版本变化时才会重新打包。 4\. Happypack,将 loader 单线程变成多线程。 5\. 通过 `webpack-bundle-analyzer` 将文件结构可视化,找出导致体积过大的原因。 6\. Webpack 中 Gzip 压缩操作的存在,事实上就是为了在构建过程中去做一部分服务器的工作,为服务器分压。 7\. ... ## 131. 代码部署 1\. Nginx - 正客反服。 - 反向代理(proxy_pass):例如 Nginx 开了 80 服务,可以配置 / => 8000/index.html、/api => 3000/api(做业务逻辑处理的 Node 服务器)。 - 负载均衡(upstream):例如可以配置 /img 到 3000/img、3001/img、3002/img 等。 ```js http { upstream backend { server backend1.example.com; server backend2.example.com; server backend3.example.com; } server { listen 80; location /img { proxy_pass http://backend; } } } ``` 2\. Node => PM2 => Docker 3\. Github Action ```yaml name: deploy-website on: push: branches: [ main ] workflow_dispatch: jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: install nodejs uses: actions/setup-node@2.5.1 with: node-version: "16.X" - name: install deps run: npm install - name: build app run: npm run build - name: copy dist file with scp uses: appleboy/scp-action@v0.0.1 with: host: ${{secrets.REMOTE_HOST}} username: ${{ secrets.REMOTE_USRE }} password: ${{ secrets.REMOTE_PASS }} port: 22 source: 'dist/' target: ${{ secrets.REMOTE_TARGET }} ``` ## 132. 监控 - sentry https://docs.sentry.io/ - fundebug https://www.fundebug.com/ ## 133. [Socket](./resource/133/README.md) ## 134. [TS 可赋值性](./resource/134/README.md) ```ts // 父类型 interface Person { name: string; age: number; } // 子类型 interface Student { name: string; age: number; stuNo: number; } let person: Person = { name: 'lei', age: 25 } let student: Student = { name: 'xiao ming', age: 8, stuNo: 11024 } // ok:子可以给父 // 原因:Student 类型的属性是完全包含 Person 类型的属性的,这样赋值后,person 可以调用他的 name, age 属性并且不会产生类型安全的问题 // person = student // error:父不能给子 // student = person // 解决:使用断言 student = person as Student ``` ## 135. 微前端 1\. iframe 通讯麻烦,借助 postMessage,刷新会导致 iframe url 状态丢失,前进后退按钮无效。 2\. qiankun JS 沙箱使用的是 proxy 进行快照,然后用 with(window){} 包裹起来 with 内的 window,其实就是 proxy.window,我们声明变量 var name = 'xxx' 实际这个变量挂载到了 proxy.window,并不是真正的 window。 CSS 沙箱原理:第一个就是 shadowDOM 隔离,第二个类似于 Vue 的 Scoped。 3\. micro-app 基于 webComponent + qiankun 的微前端方案。 4\. EMP 5\. 无界 ## 136. 服务端渲染 **注水:**在返回给客户端的 HTML 中新加个 script 标签,然后把服务端处理过的状态在 script 标签中保存在 window 全局对象里。 **脱水:**就是在客户端初始化状态前,取出 window 对象中服务端处理后的状态,作为初始状态去初始化组件的状态。 https://zhuanlan.zhihu.com/p/357538660?utm_id=0 传统服务端渲染:ASP、JSP、EJS... 同构:所谓同构,就是一套代码需要在服务端执行一遍、在客户端也执行一遍。 我们现在讲的服务端渲染,是指在前端范畴或者说在 Vue、React 等单页面技术栈范畴内,基于 Node.js 运行环境的服务端渲染方案。 通过在 Node.js 中运行相同应用程序的前端框架(例如 React、Vue 等),将其预渲染成 HTML,最后在客户端进行注水化处理。 ![111](README.assets/111.png) ## 137. Git