![](https://img-blog.csdnimg.cn/20201014180756724.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
前端面经
文章平均质量分 63
天猫精灵998
这个作者很懒,什么都没留下…
展开
-
一个案例讲解 CSS 布局两个注意点
这篇文章回顾一下 CSS 基础布局中两个注意点。有如下布局:例如我们想给 main-wrapper 内部添加上下边距,让 content 不至于紧贴盒子边缘。一种可能的方案,给 content 设置 margin:我们添加了上下各 50px 的 margin 之后发现 content 与 main-wrapper 之间并没有出现边距,反而 main-wrapper 被顶下来了。这就是第一个问题:BFC 中的垂直外边距塌陷。在同一个 BFC 中,相邻两个盒子的上下外边距会合并(可以是并排关系,也可以是原创 2022-04-04 21:02:30 · 635 阅读 · 0 评论 -
GitHub Pages 配合 GitHub Actions 实现文档网站自动部署
最近在用 docusaurus 做一个文档网站,通过 GitHub Pages 进行部署,每次部署的时候,需要在本地执行构建命令,然后将构建产物提交到 GitHub 上面,比较麻烦。因此这边用了 GitHub Action 实现持续集成。持续集成由很多操作组成,比如拉取代码、执行测试用例、登录远程服务器,发布到第三方服务等等。GitHub 把这些操作就称为 actions。我们先来了解一下一些术语:workflow(工作流程):持续集成一次运行的过程,就是一个 workflow。job(任务):一原创 2021-12-12 22:15:29 · 1797 阅读 · 0 评论 -
如何调试线上项目的代码
我们知道,通常生产环境的前端代码是经过混淆压缩的,代码本身难以阅读,但有时候排查线上 bug 需要对线上项目的代码进行调试。那么如何调试线上项目的代码呢?这边介绍两种方法。直接调试我们知道,生产环境通常会使用 uglifyJS 或者 terser 进行混淆压缩,但是这些压缩工具并不会做程序流分析,因此并不是所有的变量名、方法名都会被压缩。例如模块中有一个向外导出的方法,为确保其他模块能正常调用,这个方法名不会做混淆处理,只有该模块内部的变量名、方法名才会混淆压缩。或者在代码中的字符串字面量,也不会进行压原创 2021-12-11 21:34:15 · 1852 阅读 · 0 评论 -
浅谈 Vue3 中的 v-model 和 sync 修饰符
很多同学对 Vue 的第一印象就是“响应式”、“双向绑定”等特性,而 v-model 就是实现双向绑定的语法糖,用过 Vue 的小伙伴一定都非常熟悉。但是在 Vue3 中,v-model 发生了一些改动,使得它不再兼容 Vue2 的用法,具体是什么呢,我们一起来看看。非兼容:用于自定义组件时,v-model prop 和事件默认名称已更改:prop:value -> modelValue;事件:input -> update:modelValue;非兼容:v-bind 的 .sync原创 2021-12-06 23:53:36 · 8501 阅读 · 0 评论 -
Jest 单元测试快速入门
测试的类型单元测试集成测试端到端测试(E2E)测试 React 组件需要解决两个关键问题怎么渲染待测试组件;怎么测试渲染出来的组件;浅层渲染对于组件渲染,Airbnb 作为重度使用 React 的先驱,早就提出了专门的解决方案:Enzyme$ npm install enzyme enzyme-adapter-react-16Enzyme 提供的一个重要功能便是组件的浅层渲染(Shallow Rendering)。它允许我们在运行测试时,只渲染父组件而不渲染其所有的子组件。浅层原创 2021-11-17 16:31:32 · 605 阅读 · 0 评论 -
Webpack 模块方法——require.context
在 Webpack 中,除了可以使用 import 、export 等模块语法之外,还可以使用 Webpack 提供的模块方法。其中使用最多的是 require.context 。在项目中经常会遇到一个问题,组件库导入、路由注册等需要手写大量 import ,比较麻烦。这种情况下就可以使用 require.context 。require.context( (directory: String), // 检索目录 (includeSubdirs: Boolean), // 是否检索子文件夹,默认原创 2021-11-13 21:08:37 · 1150 阅读 · 0 评论 -
面试官:什么时候不能使用箭头函数
今天看到这个面试题,特别有意思。一般来说面试官应该问的是箭头函数和普通函数的区别,这样应该大多数人都能答得上来,但是现在反过来,考验逆向思维,很多人可能都一下子反应不过来。我们先来回顾一下箭头函数和普通函数的区别:箭头函数没有自己的 this ,没有 argument 对象,没有 prototype ,不能作为构造函数(用 new 调用会报错)。箭头函数会自动捕获上级词法作用域的 this ,并且箭头函数的 this 在声明的时候就已经确定了,不能通过 call 或者 apply 修改。因此以下场景不原创 2021-11-08 22:22:13 · 1254 阅读 · 0 评论 -
TS 实现简易的 tapable
type TapEvent = string;type Handler = () => void;type EventCenter = Record<TapEvent, Handler>;interface IHook { tap: (name: TapEvent, func: Handler) => void; call: (name?: TapEvent) => void;}class SyncHook implements IHook { pri原创 2021-11-04 20:28:56 · 199 阅读 · 0 评论 -
手写一个简单的静态资源服务器
写了一个简单的静态资源服务器,如果文件不存在或者路径是一个目录,则返回错误信息。这里有两个特点:使用 async-to-js 进行异常处理;使用 stream ,通过 pipe 方法将 Readable 写入到 Writable ,避免 Readfile 方法一次性将整个文件加载到内存中;后期需要在响应头中加上 Content-Type 。const http = require("http");const path = require("path");const fs = require(原创 2021-10-29 20:30:25 · 113 阅读 · 0 评论 -
如何给开源项目提 PR
1. fork 仓库首先需要 fork 仓库。然后把 fork 之后的仓库克隆到本地。等待数秒,仓库就fork好了,可以看到个人仓库名称的下面有一个:forked from DevUI/vue-devui2. 配置 SSH 公钥,clone 代码配置好SSH公钥,即可以clone代码啦。3. 设置upstream和同步源仓库最新代码查看远程仓库地址:$ git remote -v默认情况下clone的仓库有以下两个远程地址:$ git remote -vorigin gi原创 2021-10-28 10:37:48 · 590 阅读 · 0 评论 -
GitHub 如何 pull request
这里以添加 LICENSE 为例,讲解如何使用 pull request 。建一个测试仓库,点击 add file :点击 create new file ,进入如下界面,左边输入大写 LICENSE ,右边会出现一个按钮,点击一下:选择 MIT LICENSE :然后会生成一份协议模板,根据右边的值进行填充:生成最终协议,注意下面的选项,会创建一个新分支,然后自动发起 pull request ,点击 commit new file :这边进入 pull request 界面,ad原创 2021-10-24 22:55:35 · 2435 阅读 · 0 评论 -
你不知道的 JS 代码小技巧
总结了一些开发常用的 JS 小技巧,让你的代码更优雅!1. 通过条件判断给变量赋布尔值先来看一段代码:handleFormChange(e) { let isUpload; if (e.target.value === 'upload') { isUpload = true; } else { isUpload = false; }}在项目中很多同事都会这样写,但实际上 == 和 === 的表达式可以直接给变量赋值:handleFormChange(e) {原创 2021-10-19 20:29:27 · 127 阅读 · 0 评论 -
从 async/await 看 redux-saga 原理
最近看了一篇神光大佬的文章:为什么 redux-saga 不能用 async await 实现 ,看完之后深有体会。虽然这篇文章没有讲具体实现原理,但是总结了两个浅显易懂的道理:async/await 本质上是一个 generator 的自动执行器,没有 runtime 逻辑;saga 实际上也是实现了 generator 执行器,但是有自己的 runtime ,可以将异步过程抽离出来,便于测试;那么很显然,搞懂 async/await 原理,redux-saga 的原理自然也就搞清楚了。1.原创 2021-10-12 20:34:47 · 275 阅读 · 0 评论 -
设计模式系列:从实际项目需求谈谈代理模式/装饰器模式
问题引入在项目中有一个需求,某个方法的执行需要加上权限判断:const clusterExapnd = () => { console.log("集群扩容操作");}相信很多人一定都会这样写:const clusterExapnd = () => { if (loginUser !== "admin") { console.log("当前用户没有操作权限!"); return; } console.log("集群扩容操作");}在上面这个简单的场景中,这样写原创 2021-09-26 20:33:12 · 185 阅读 · 0 评论 -
设计模式系列:策略模式
昨天在调试同事开发的页面,发现有很多 404 的请求,看了下 Network 面板有点哭笑不得,原来是前端把页面路由当成后台接口请求了,后台肯定不存在对应的资源,因为是前端路由。那么为什么会发送这样的请求呢?我看了下同事写的代码,由于这边的需求是需要同时支持 mock 环境和正常后台环境,然后根据传递的 query 字段选择合适的接口进行请求。然鹅看到代码就惊呆了,各种 IF ELSE 和 SWITCH CASE ,夸张的是同事告诉我这是他能想到的最优方案(手工狗头)const isMockEnv =原创 2021-09-25 12:36:46 · 245 阅读 · 0 评论 -
Chrome devtool 火焰图的看法
我们知道某个函数的执行路径是有 call stack 的,可以看到从哪个函数一步步调用过来的,是一条线。但其实这个函数调用的函数并不只一个,可能是多个:调用栈只是保存了执行到某个函数的一条路线,而火焰图则保存了所有的执行路线。所以你会在火焰图中看到这样的分叉:其实就是这样的执行过程:来算一道题:函数 A 总耗时 50 ms,它调用的函数 B 耗时 10 ms,它调用的函数 C 耗时 20 ms,问:函数 A 的其余逻辑耗时多少 ms?很明显可以算出是 50 - 10 - 20= 20原创 2021-09-23 19:31:22 · 588 阅读 · 0 评论 -
Node 中的 ReadStream 和 WriteStream
之前看别人用 Koa 实现文件下载功能,直接将 Readable Stream 传给 ctx.body :const fs = require('fs');const Koa = require('koa');const app = new Koa();app.use(async ctx => { try { ctx.body = fs.createReadStream(resolve(__dirname, 'test.json')); } catch (err) {原创 2021-09-08 14:50:35 · 1299 阅读 · 0 评论 -
基于发布订阅模式实现 time 和 timeEnd 方法
相信很多同学都用过 console.time 和 console.timeEnd 方法统计代码运行时间。这边本人利用发布订阅模式模拟实现 time 和 timeEnd 方法,代码如下:class MyConsole { constructor() { // 全局事件中心 // 采用先订阅后发布的模式 this.events = {}; } time(s) { let timeStart = new Date().getTime(); // 订阅事件原创 2021-08-24 13:39:10 · 207 阅读 · 0 评论 -
React Suspense 在异步获取数据方面的应用
写这篇文章之前,实在想吐槽一下 React 官方文档,很多 API 的介绍都是不明不白的,不看之前有一堆问号,看完之后问号更多了。项目需求最近在开发一个大数据运维的项目,需要展示大量的 echarts 图表。由于从后台调接口返回数据需要时间,然后前端对数据的处理也需要时间,这样就导致了页面加载的延迟。希望可以做一个整页的 loading ,在图表渲染完成之后展示图表内容。最近在看 ssh 大佬写的一篇文章:React Suspense + 自定义Hook开启数据请求新方式看完之后深受启发,希望可以借原创 2021-08-22 23:34:56 · 1073 阅读 · 0 评论 -
TS如何获取第三方库未导出的 Type
在使用 antd 组件的时候,同事遇到一个问题,Radio 组件的 onChange 事件处理函数,传递的参数是一个事件对象,无法推导类型:import { Radio } from "antd";import * as React from "react";type Props = { name: string;}const HelloWorld: React.FC<Props> = ({ name }) => { const [value, setValue]原创 2021-08-12 23:28:36 · 1725 阅读 · 0 评论 -
JS 时间格式化 api 的性能问题
哪种时间格式化 API 的性能最好,原生 API 性能一定好于第三方库吗发现问题在项目中有一个需求,需要绘制 CPU 占用和时间关系的 line chart ,数据量在几万到几十万级别。由于后台返回的是时间戳,需要在前端进行格式化。在前端进行时间格式化,下面几种都是常用的 API :// 使用 moment 第三方库moment(new Date()).format("hh::mm");// 使用 getHours + getMinuteslet now = new Date();[now.原创 2021-08-16 21:09:20 · 303 阅读 · 0 评论 -
TypeScript 使用 infer 实现类型推断
首先从一个问题引入,我们怎样拿到下面 Promise 内部包裹的类型呢?function request(req: string): Promise<string> { return new Promise(resolve => setTimeout(() => resolve(req), 3000))}很多同学上来就用 typeof 和 ReturnType 一把梭哈:type Request = typeof request; // type Request =原创 2021-08-16 11:29:40 · 1174 阅读 · 0 评论 -
yarn 包管理工具的使用
yarn 是什么“Yarn是由Facebook、Google、Exponent 和 Tilde 联合推出了一个新的 JS 包管理工具 ,正如官方文档中写的,Yarn 是为了弥补 npm 的一些缺陷而出现的。”这句话让我想起了使用npm时的坑了:npm install的时候巨慢。特别是新的项目拉下来要等半天,删除node_modules,重新install的时候依旧如此。同一个项目,安装的时候无法保持一致性。由于package.json文件中版本号的特点,下面三个版本号在安装的时候代表不同的含义。原创 2021-08-14 18:15:30 · 480 阅读 · 0 评论 -
CSS 绘制三角形和带边缘色的气泡聊天框
CSS 绘制三角形先画一个正方形:<div class="filled-triangle"></div>.filled-triangle { width: 100px; height: 100px; border: 1px solid cyan;}然后将宽高均设为0,只留下四个 border :.filled-triangle { width: 0; height: 0; border-bottom: 50px solid cyan; b原创 2021-08-12 20:11:40 · 664 阅读 · 0 评论 -
深拷贝如何解决循环引用的情况
在看 Vuex 源码的时候看到里面有个 deepCopy 的实现,里面解决了循环引用的问题。本人对源码进行了优化,一起看一下是怎么实现的:function deepCopy (obj, cache=[]) { // 结束递归 if (obj === null || typeof obj !== 'object') return obj // 缓存命中,说明存在循环引用的情况 var hit = cache.filter(c => c.original === obj)[0];原创 2021-07-29 23:04:47 · 889 阅读 · 1 评论 -
手写题:实现数组的 map,filter 和 reduce 方法
1. 实现数组的 filter 方法/** * 实现数组的 filter 方法 * @param {Function} callback (item: T, index: number, array: T[]) => boolean * @returns T[] */Array.prototype.myFilter = function (callback) { let len = this.length; let i = 0; let result = [];原创 2021-07-25 12:35:22 · 226 阅读 · 0 评论 -
TypeScript 中几个小技巧
泛型的用法本来以为在开发中基本用不到泛型,没想到今天还是碰到了。公司的项目是用 React 写的,其中需要使用 useSelector 的 hook 从 redux 获取数据,代码如下:const { auditFilterOptions, auditRecords, auditTableLoading } = useSelector(state => { auditFilterOptions: state.getIn(["resource", "auditFilterOptions"]),原创 2021-07-21 17:56:13 · 425 阅读 · 0 评论 -
如何编写 TypeScript 声明文件
1. 什么是 TS 声明文件在 TypeScript 中以 .d.ts 为后缀的文件,称为 TypeScript 声明文件。它的作用是描述 JavaScript 模块内所有导出接口的类型信息。2. 什么时候需要写 TS 声明文件在使用 TypeScript 开发的项目中,常常需要引入公共模块,或者第三方库。如果这些公共模块或第三方库是用 JS 写的,那么 TS 就无法检测到类型信息,在编译阶段会报错。这时候有人会说,能不能将这些公共模块或第三方库的代码用 TS 重写呢?答案是不行,因为重写之后,使用原创 2021-07-18 16:23:07 · 2248 阅读 · 1 评论 -
TypeScript 快速入门
考虑到现在项目中主要使用 JS ,以及 TS 的学习成本,采用渐进式迁移的方案,允许使用 JS 或 TS 编写组件代码,对使用 TS 编写的组件进行编译。如果是自己搭建的项目,可以参考以下方案:Webpack 转译 Typescript 现有方案有了 @babel/preset-typescript ,配置 TypeScript 环境确实方便了很多。需要注意的是,@babel/preset-typescript 只做语法转换,不做类型检查,因为类型检查的任务可以交给 IDE (或者用 tsc)去做。原创 2021-07-13 22:29:17 · 195 阅读 · 0 评论 -
babel-plugin-import 实现按需引入
为什么需要这个插件在 antd 和 element 两个组件库中,index.js 分别是这样的:// antdexport { default as Button } from './button';export { default as Table } from './table';// elementimport Button from '../packages/button/index.js';import Table from '../packages/table/index.js原创 2021-07-07 22:31:23 · 1966 阅读 · 0 评论 -
Spring的Controller是单例还是多例?怎么保证并发的安全
Spring 的 Controller 默认是单例的,不要使用非静态的成员变量,否则会发生线程安全问题,导致数据逻辑混乱。正因为单例所以不是线程安全的。下面来简单验证下:@Controllerpublic class ScopeTestController { private int num = 0; @RequestMapping("/testScope") public void testScope() { System.out.println(++num转载 2021-07-03 11:13:58 · 142 阅读 · 0 评论 -
使用 JS 实现一个发布订阅模式
实现一个 Event ,示例如下:const e = new Event();e.on("click", x => console.log(x.id));e.emit("click", { id: 3 }); // 3e.emit("click", { id: 4 }); // 4一个简单的发布订阅模式实现如下,主要有两个核心 APIemit 发布一个事件on 监听一个事件class Event { // Events<String, Function[]>原创 2021-07-02 22:17:30 · 297 阅读 · 0 评论 -
阿里面试官:了解过 CSS 加速渲染吗
随着互联网和电子硬件设备的不断发展,Web 应用的交互也越来越复杂(代码层面),为了得到最佳体验 Web 应用开始使用更多的动画(例如 animations 、transforms 、transitions 等)来做顺畅的交互,但这也给浏览器增加了额外的负担。庆幸的是现在大多数计算机设备不仅有强大的 CPU 而且有了专门为图形计算而生的 GPU,我们可以充分发挥 GPU 的实力,来让我们的 WEB 应用更佳的流畅。桌面端使用 CSS 硬件加速默认情况下,CSS animations, transform原创 2021-07-01 22:38:21 · 86 阅读 · 0 评论 -
JS 合并两个数组常用方法(其中一个你肯定没用过)
在 JS 中,如果要将一个数组合并到另一个数组,通常会用到如下方法:const arr1 = ["a", "b"];const arr2 = [1, 2];const arr = [...arr1, ...arr2];// orconst arr = arr1.concat(arr2);// orconst arr = arr1.push(...arr2);今天看到了一个方法,使用 apply:const arr = [].push.apply(arr1, arr2);由于 app原创 2021-06-30 22:05:50 · 681 阅读 · 0 评论 -
CSS 三种布局遇到的坑
1. 图片设置 border-radius 不生效通常 img 标签外面会包裹一个 div ,方便用来布局。但是给这个 div 设置 border-radius 却发现不生效。<div class="profile-image"> <img class="img" src="https://img01.yzcdn.cn/vant/cat.jpeg" alt="" /> </div>.profile-image { width: 100px; height:原创 2021-06-27 12:45:51 · 1465 阅读 · 0 评论 -
JS 五种方法访问数组最后一个元素
在开发的时候经常需要访问数组的最后一个元素,这里总结一下常用的方法。1. 使用 arr[arr.length - 1]首先最常规的方法就是使用 arr[arr.length - 1] ,缺点就是这样写太长了,例如下面这个数组:const lastEle = this.form.users[this.form.users - 1];2. 使用 slice 方法数组实例的 slice 方法返回一个由 begin 和 end 组成的闭开区间的新数组,如果 end 被省略,则 slice 会一直提取到原创 2021-06-25 19:29:52 · 16385 阅读 · 0 评论 -
前端开发专属的高考题
选择题下列关于前端工程师的概括最恰当的是:A. 做客户端的(app 端)B. 做网站的C. 做接口开发的下列关于 V8 JavaScript 和 Node.js 说法正确的是:A. V8 JavaScript 是面向浏览器编程,Node.js 是面向操作系统编程B. V8 JavaScript 是面向操作系统编程,Node.js是面向浏览器编程对于静态资源,下列说法正确的是:A. 通常 HTML、JS、CSS、图片、字体等都属于静态资源B. 由于 Node.js 可在服务器端原创 2021-06-12 20:02:46 · 1112 阅读 · 4 评论 -
JS 实现数组元素随机取样
这几天遇到了需要从数组中随机取样的需求,看别人写的很复杂,于是自己写了一个:Array.prototype.sample = function() { if (!this.length) return; let rand = Math.floor(Math.random() * this.length); return this[rand];}写个方法测试一下:class Test { constructor() { this.redCount =原创 2021-06-08 20:10:00 · 1067 阅读 · 0 评论 -
Vue SFC CSS 变量注入提案 (SFC CSS variable injection)
在 Vue 中想要实现动态样式绑定,基本只能通过设置行内样式来实现:<template> <div class="header" :style="{'color': color, 'font-size': size}">测试内容</div></template><script>export default { data() { return { color: 'red', size: 24 } }}</原创 2021-06-08 18:02:57 · 1249 阅读 · 2 评论 -
前端面试题:每隔一秒打印依次打印0, 1, 2...
一道非常经典的前端面试题,实现比较简单但是会涉及事件循环、块级作用域、闭包等知识点。通常面试官会给你一段已经写好的代码,然后问你存在什么问题,是什么原因,有哪些方法让它正常输出。例如下面这段代码,看起来没有问题,但是运行之后会发现,每隔一秒打印的都是10:for (var i=0; i<10; i++) { setTimeout(_ => { console.log(i) }, i*1000)}// 10 10 10 10 10 10 10 10 10 1原创 2021-06-08 13:30:51 · 1471 阅读 · 1 评论