HTML
如何理解 HTML 语义化 ?
仅通过标签便能判断内容的类型,特别是区分标题、段落、图片和表格
- 增加代码可读性(让人更容易读懂)
- 对SEO更加友好 (让搜索引擎更容易读懂)
HTML有哪些内联元素和块状元素 ?
内联元素
宽度由内容决定
display :inline
若非替换元素,不能设置宽高
img,span , a 等
display :inline-block
可以设置宽高
input, button 等
块状元素
宽度由容器决定(宽度会撑满整个容器),可以设置宽高
display: block
div,h1-h6,p,ul, ol ,form , hr 等
display: table
table
display: list-item
li
HTML5 新增了哪些标签 ?
<header>: 定义文档或节的头部。
<nav>: 定义导航链接。
<section>: 定义文档中的独立节。
<article>: 定义文档、页面、应用或网站中独立的内容区域。
<aside>: 定义页面的侧边栏内容。
<footer>: 定义文档或节的页脚。
<main>: 定义文档的主体内容。
<video>: 定义视频或电影。
<audio>: 定义音频内容。
<source>: 为<video>和<audio>元素定义媒体资源。
<embed>: 定义嵌入的内容,比如插件。
<canvas>: 用于在网页上绘制图形。
为什么
<style></style>
标签要写在<head></head>
中 ?
浏览器解析 HTML 文档是自上而下的,将 <style></style>
标签要写在<head></head>
中就能先加载样式,再加载元素。
若将 <style></style>
标签写在<body></body>
下方,则是先加载元素,再加载样式,导致用户会看到没有样式的页面结构。
- 避免 DOM Tree 重复渲染,提升页面渲染速度
- 避免页面样式的闪烁和混乱现象
为什么
<script></script>
标签要写在<body></body>
内的底部 ?
浏览器解析 HTML 文档是自上而下的, <style></style>
若未放在<body></body>
内的底部,则会先加载并解析 JS ,再渲染元素,导致页面渲染的时间延长,倘若 JS 中涉及 DOM 操作,还会阻塞页面的渲染。
script 标签中 defer 和 async 的区别
CSS
行高 line-height 的继承
- 值为具体数值,如 30px,则继承该值,子元素的line-height也是 30px
- 值为比例,如2或1.5,则继承该比例,子元素的line-height也是 2或1.5
- 值为百分比,如 200%,则继承父元素计算后的值 ( 百分比* 父元素的 font-size )
盒模型
- 标准盒模型
width 和 height 指的是内容区域的宽度和高度
box-sizing:content-box;
- IE 盒模型
width 和 height 指的是内容区域+border+padding的宽度和高度。
box-sizing:border-box;
margin
margin 负值的效果
- margin-top 负值,元素向上移动
- margin-left 负值,元素向左移动
- margin-right 负值,右侧元素左移,自身不受影响
- margin-bottom 负值,下方元素上移,自身不受影响
margin 合并
- 相邻兄弟元素垂直方向 margin 会合并,保留较大的 margin 。
- 父级和第一个/最后一个子元素垂直方向 margin 会合并,保留较大的 margin 。
- 空块级元素的垂直方向 margin 会合并
margin 合并的计算规则
- 两个正/负margin合并,取绝对值最大的margin
- 一正一负的margin,则相加求和得到最终的margin
定位 position
- 静态定位 position: static 【默认】
- 相对定位 position: relative
- 依据自身位置定位
- 绝对定位 position: absolute
- 依据最近一层的定位元素(position 值为 absolute/relative/fixed 的元素)定位,若无定位元素,则依据body定位
- 固定定位 position: fixed
- 黏性定位 position: sticky
布局 display
BFC 块级格式化上下文
形成一块独立的渲染区域,内部元素的渲染不会影响外部元素,也不会被外部元素影响
触发BFC的方法
满足以下任意一个条件即可
- html根元素;
- float的值不为 none;
- overflow的值不为 visible (即值为auto / scroll / hidden【推荐】)
- display的值为 flex / inline-block / table-cell / table-caption
- position的值为 absolute / fixed
BFC布局的特点
- 不会发生margin重叠
- 可以清除浮动
- 实现更健壮、更智能的自适应布局
响应式布局
- 【推荐】媒体查询 + rem + flex
- vh + vw
- 百分比
- 【不推荐】JS 动态计算
变换 transform
transform: translate(水平位移, 垂直位移);
// 绝对定位元素的 -- 水平垂直居中
.dialog {
position: absolute;
left: 50%; top: 50%;
transform: translate(-50%, -50%);
}
transform: scale(水平方向的缩放倍数, 垂直方向的缩放倍数)
transform: rotate(45deg); // 顺时针旋转 45 度
对齐
内联元素:display 的计算值为 inline、inline-block,inline-table 或 table-cell 的
- 水平方向 text-align
- 垂直方向 vertical-align
块级元素
- 水平居中 margin: auto;
- 水平垂直居中
- flex
- flex 布局 + 自动外边距
- grid 布局
- grid 布局 + 自动外边距
- 单元格布局 + 自动水平外边距
- 子绝父相 + 上下左右0 + 自动外边距
- 子绝父相 +
transform: translate
- 子绝父相 + margin 偏移
样式优先级
-
5级—— !important
-
4级—— style 内联样式
-
3级—— ID 选择器
-
2级—— 类选择器、属性选择器和伪类
-
1级——标签选择器
-
0级——通配选择器 *、逻辑组合伪类,如 :not()、:is() 和 :where 等
-
优先级最低 —— 继承的样式
CSS 自测题
https://blog.csdn.net/weixin_41192489/article/details/136372234
手写 CSS
-
【实战】 “四合院”布局-CSDN博客
https://blog.csdn.net/weixin_41192489/article/details/139243680 -
【实战】用 flex 布局绘制骰子(一、二、三【含斜三点】、四、五、六点)
https://blog.csdn.net/weixin_41192489/article/details/136398234 -
【实战】圣杯布局 vs 双飞翼布局 (含手写清除浮动 clearfix)
https://blog.csdn.net/weixin_41192489/article/details/136376716 -
【实战】抽屉动画-CSDN博客
https://blog.csdn.net/weixin_41192489/article/details/139785738
JS
ES6 新增语法
- let 替代 var 声明变量(避免变量提升),const 声明常量
- 新增数据类型 Symbol
- 新增数据结构 Map Set
- 箭头函数 => (简化函数的写法,明确 this,更适合函数式编程)
- 模板字符串 `` (字符串里写变量)
- Promise 处理异步 (避免回调地狱)
- 解构赋值
- 模块化 export import
- Class 类
- 新增 Array.of() 创建数组,避免 new Array() 传入单个
- for of 循环
- Object.is
ES6 模块规范 vs CommonJS 模块规范
特性 | CommonJS | ES6 模块化 |
---|---|---|
导入的语法 | require() 函数 | import 关键字 |
导出的语法 | exports 对象 | export 关键字 |
导出的内容 | 值的拷贝 | 值的引用 |
导入导出的形式 | 只支持整个模块 | 支持命名的模块成员、默认导出和命名空间 |
加载模式 | 同步 | 异步 |
执行模式 | 单例 | 单例 |
依赖关系 | 运行时解析和执行 | 在静态阶段编译并分析 |
树形摇晃 | 不支持 | 支持 |
var 和 let const 的区别
- var 是 ES5 语法,会导致变量提升,let 和 const 是 ES6 语法
- var 和 let 用于声明变量,可修改; const 用于声明常量,不可修改;
- let 和 const 有块级作用域,var 没有
变量提升
执行 js 代码时,会先将所有 var 定义的变量赋值为 undefined(相当于提升到代码最前面执行)
console.log(a); // 打印 undefined
var a = 1;
现象:var 定义的变量在声明前使用也不会报错
// 声明全局变量 a,并赋值 123
var a = 123;
function f() {
// 因 var 变量提升的特性,此时打印的 a 是函数作用域内的局部变量 a
console.log(a); //打印结果:undefined
// 函数作用域内声明局部变量 a (虽和全局变量 a 的名称相同,但却是不同的变量!),并赋值 1
var a = 1;
// 打印函数作用域内的局部变量 a
console.log(a); //打印结果:1
}
f();
// 打印全局变量 a
console.log(a); //打印结果:123
async 和 defer 属性的区别
- async 浏览器异步下载并立即执行JS文件,适用于不依赖于文档其他部分的脚本。
- defer 浏览器异步下载JS文件,但要等HTML文档完全解析完毕才开始执行。
如何准确判断一个变量是数组
变量 instance of Array
事件相关的考点
https://blog.csdn.net/weixin_41192489/article/details/136610476
- event.preventDefault() 阻止默认行为
- event.stopPropagation() 阻止事件传播(冒泡/捕获)
window.onload 和 DOMcontentLoaded 的区别
同【考题】document load 和 ready 的区别
window.addEventListener("load", function () {
// 页面的全部资源加载完才会执行,包括图片视频等
});
document.addEventListener("DOMContentLoaded", function () {
// DOM 渲染完即可执行,此时图片、视频可能还没有加载完
});
如何提升 DOM 的性能?
- 对 DOM 的查询做缓存
- 将多个 DOM 操作合并为一次操作
内存泄漏
-
WeakMap和 WeakSet 的作用 :防止内存泄漏,使用场景:临时记录数据或关系
-
怎样的 js代码会导致 “栈溢出” ?如递归次数太多
-
怎样避免递归次数太多导致栈溢出(爆栈) ? 使用尾递归(将递归写在函数的尾部)
如何捕获 JS 中的异常 ?
- 手动捕获 try catch
- 自动捕获 window.onerror
JS 算法
-
JS【详解】时间复杂度-CSDN博客
https://blog.csdn.net/weixin_41192489/article/details/139355251 -
JS【详解】快速排序-CSDN博客
https://blog.csdn.net/weixin_41192489/article/details/139357440 -
JS 【详解】双指针排序 – 数组合并后递增排序-CSDN博客
https://blog.csdn.net/weixin_41192489/article/details/139358291 -
JS 实现动态规划-CSDN博客
https://blog.csdn.net/weixin_41192489/article/details/139590789 -
JS 【算法】二分查找-CSDN博客
https://blog.csdn.net/weixin_41192489/article/details/139622826 -
JS 【详解】树的遍历(含深度优先遍历和广度优先遍历的算法实现)-CSDN博客
https://blog.csdn.net/weixin_41192489/article/details/139862682 -
JS 【详解】二叉树(含二叉树的前、中、后序遍历技巧和算法实现)-CSDN博客
https://blog.csdn.net/weixin_41192489/article/details/139626496 -
用栈翻转字符串
https://blog.csdn.net/weixin_41192489/article/details/139855089
浏览器
浏览器中输入 url 渲染页面的过程
- 进行域名解析(DNS解析),通过 url 找到目标服务器的 IP 地址
- 浏览器向目标 IP 地址的服务器发起 http 请求
- 服务器处理 http 请求,并返回给浏览器
- 浏览器根据服务器返回的内容,下载相关的资源,内容有html,css,JavaScript,图片,视频等
- 浏览器根据 HTML代码生成 DOM Tree
- 浏览器根据 CSS 代码生成 CSSOM (CSS对象模型)
- 浏览器将 DOM Tree 和 CSSOM 整合形成 Render Tree
- 浏览器根据 Render Tree 渲染页面
- 渲染页面过程中,若遇到 JS 代码会暂停渲染,优先加载并执行 JS 代码,完成后再继续渲染
- 直至把 Render Tree 渲染完
Cookie、sessionStorage、localStorage的区别
Cookie | sessionStorage | localStorage | |
---|---|---|---|
存储大小 | 4kb内 | 5M内 | 5M内 |
数据有效期 | 可自定义失效时间,默认是关闭浏览器后失效 | 仅在当前会话下有效,关闭页面或浏览器后被清除 | 永久有效,除非代码/手动删除 |
服务器通信 | 携带在HTTP头中,在浏览器和服务器中来回传递 | 仅在本地存储,不和服务器通信 | 仅在本地存储,不和服务器通信 |
Vue2
data 为何必须是一个函数 ?
每个 vue 文件都是一个类,使用 vue 文件时,会对类实例化,若 data 不是函数,会导致 data 被所有实例共享,一个实例中的 data 改变,也会引发其他实例中的 data 也发生改变!
当 data 是函数时,在类实例化的过程中会形成闭包,避免了不同实例间 data 的相互影响。
computed 的特点
有缓存,data 不变时不会重新计算,从而提高了性能。
使用注意事项:
- v-model 绑定的自动计算变量,必须同时写 get 和 set
<template>
<div>
<p>num {{ num }}</p>
<p>double1 {{ double1 }}</p>
<input v-model="double2" />
</div>
</template>
<script>
export default {
data() {
return {
num: 20,
};
},
computed: {
double1() {
return this.num * 2;
},
double2: {
get() {
return this.num * 2;
},
set(val) {
this.num = val / 2;
},
},
},
};
</script>
watch
默认是浅监听 (引用类型才需要深度监听)
监听引用类型的变量时,拿不到 oldValue ,因为引用类型的值改变时,并没有改变引用的地址,得到的 oldValue 和 newValue 相同。
v-show和 v-if 的区别
- v-show 通过移除/添加display:none样式,来显示/隐藏元素,适合频繁切换显隐的情况,有较高的渲染成本(v-show="false"时,该节点也会被创建)
- 元素若是子组件,元素mounted及之前生命周期中的代码会在整个页面初次渲染时就执行,后期切换显隐的过程中,不会再执行
- v-if 通过添加/删除DOM元素,来实现显示/隐藏元素,适合无需频繁切换显隐的情况,有较高的切换成本(每次切换,都需重新渲染节点)
- 元素若是子组件,元素mounted及之前生命周期中的代码在每次显示元素时都会执行
为何 v-for 中要用 key
v-for 必须用 key,且不能是 index和 random 随机数
因为diff 算法中通过 tag 和 key 来判断,是否是同一个节点,使用 key 能减少渲染次数,提升渲染性能。
-
为何 v-for 的 key 不能是 index ?
- 数组中部插入/删除一个元素时,后续元素的下标也会发生变化,这会引发 diff 算法 的误判,未发生变化的元素也会重新渲染,导致渲染性能降低
- 在某些场景中(比如含输入框时)会引发 diff 算法 的误判,导致页面错误的渲染。
-
为何 v-for 的 key 不能是 random 随机数 ?
随机数每次都不一样,无需更新的节点,也会被 diff 算法视为发生了变化而重新渲染 ,导致渲染次数增加,渲染性能降低。
v-if 和 v-for 为什么不能一起用?
vue2 中 v-for 的优先级高于 v-if ,若一起用会造成性能浪费
解决方案:v-if 放在 v-for 所在标签的内层或外层。
<ul>
<template v-for="(item,index) in ['国庆节', '春节', '元旦']">
<li v-if="item !== '春节'" :key="item">{{item}}</li>
</template>
</ul>
- 将 v-for 写在 template上,key和 v-if 写在循环遍历的元素上
- template上不能使用key, 但 v-for 必须要指定key,所以循环遍历的元素上,需要加上key
vue3 可以一起用,因为 vue3 中 v-if 的优先级高于 v-for
Vue 组件如何通讯
- 父子组件通信
- props 父组件通过动态属性,给子组件传值
- $emits 子组件通过事件给父组件信息
- 兄弟组件通信 – 自定义事件
- 第三方库 – vuex
生命周期
https://blog.csdn.net/weixin_41192489/article/details/136549141
ajax 请求应该放在哪个生命周期
答案:mounted
解析:因为 JS 是单线程的,ajax 是异步获取数据,放在 mounted 之前,并没有很好的效果,只会让逻辑更加混乱。
何时需要使用 beforeDestory
(都是为了避免内存泄露)
-
清除定时器
-
解绑自定义事件 event.$off
-
解绑全局事件
使用 addEventListener 给 window / document 添加的事件
自定义 v-model
https://blog.csdn.net/weixin_41192489/article/details/136942322
v-model 的实现原理
v-model 默认会占用名为 value 的 prop 和名为 input 的事件
- 修改变量时,变量的值通过名为 value 的 prop 传给 input 标签,触发 input 输入框内容的改变
- 修改输入框的内容时, 会触发 input 事件,将 $event.target.value 的值实时赋值给变量,并驱动页面更新。
$nextTick
- Vue 是异步渲染(可以提高渲染性能)
- data 改变之后,DOM 不会立刻渲染,页面渲染时会将 data 的修改做整合,多次 data 修改只会渲染一次
- $nextTick 会在 DOM 渲染之后被触发,以获取最新 DOM 节点(更新后的DOM,只能在 $nextTick 的回调中获取到)
slot 插槽
https://blog.csdn.net/weixin_41192489/article/details/136944943
何时要使用异步组件?
异步组件:指通过异步方式加载的组件,即仅在使用组件时,才开始加载和渲染组件,可以提高用户体验,加快页面的载入速度,提升vue性能。
components: {
AsyncComponent: () => import("./components/asyncComponent.vue"),
},
使用场景如下:
- 加载大组件,如图表、富文本编辑器等
- 路由异步加载
何时需要使用 keep-alive ?
- 需要缓存组件时使用,如多个静态 tab 页的切换,可以提升 vue 性能。
多个组件有相同的逻辑,如何抽离?
答案:使用 mixins
Vue 性能优化
- 渲染列表时加 key
- 及时销毁自定义事件、DOM 事件
- 合理使用异步组件
- 使用服务端渲染 SSR
- webpack 中使用 production,打包时自动删掉调试代码
- 前端通用的性能优化,如图片懒加载
Vue3
Vue3 比 Vue2 有什么优势 ?
- 性能更好
- 体积更小
- 更好的 ts 支持
- 更好的代码组织
- 更好的逻辑抽离
- 更多新功能
vue3 比 vue2 快的原因
- 使用 Proxy 实现响应式
- vue3 对动态节点添加了标记,提升了 diff 算法的性能
- 缓存静态节点 hoistStatic,提升编译速度
- 缓存事件 cacheHandler,提升编译速度
- 优化了 SSR(静态节点直接输出)
- tree-shaking 按需编译
Vue3 升级了哪些重要的功能 ?
- 新增 Composition API (组合式 API)
- 响应式状态声明 ref, reactive
- readonly 创建只读代理
- watchEffect
- 生命周期钩子
- 改用 createApp 初始化实例
- 新增 emits 选项(自定义事件的名称,需用 on 开头)
- 新增模板片段 fragment(支持多个根节点)
- 移除数据双向绑定修饰符 .sync,改用 v-model:
- 改用 defineAsyncComponent 导入异步组件
- 移除 filter
- 新增内置组件 Teleport(用于将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去,常用于模态框的开发。)
- 新增内置组件 Suspense(用于展示异步组件的状态)
组合式 API
更适用于逻辑复杂的大型项目
应该使用组合式 API 还是选项式 API ?
- 不建议共用,会引起混乱
- 小型项目、业务逻辑简单,用选项式 API
- 中大型项目、逻辑复杂,用组合式 API
与选项式 API 相比,有哪些优势?
- 更好的代码组织
- 更好的逻辑复用
- 更好的类型推导
组合式 API 如何实现逻辑复用?
- 抽离逻辑代码到一个函数
- 函数命名约定为 useXxxx格式 (React Hooks 也是 )
- 在 setup 中引入 useXxx 函数
如何理解 ref ,toRef 和 toRefs
- ref 是创造响应式,可对所有类型的数据声明响应式。
- toRef 是延续响应式,基于响应式对象上的指定属性,创建 ref
- toRefs 也是延续响应式,基于响应式对象上的所有属性,创建 ref
vue3 组件通信有哪些方法?
- 【父传子】props
- 【子传父】$emit
- 【父传子】$attr
- 【子取父】$parent
- 【父取子】$refs
- 【父传后代】provide/inject
https://blog.csdn.net/weixin_41192489/article/details/140566761 - 【父子双向绑定】v-model
- 【任意关系的组件通信】自定义事件
- 【任意关系的组件通信】Vuex
- 【任意关系的组件通信】Pinia
https://blog.csdn.net/weixin_41192489/article/details/140093389
vue3 的生命周期
- onBeforeMount(已经完成了响应式状态的设置,可以进行Ajax请求,已生成vdom,还没开始渲染 DOM)
- onMounted(已完成同步组件的 DOM 渲染,不包含异步组件或 树内的组件,更适合进行Ajax请求,因为可以操作DOM )
- onBeforeUpdate(响应式状态已变化,还没开始渲染新 DOM,用于在更新 DOM 之前访问 DOM 状态)
- onUpdated(因 vue 是异步更新,所以访问更新后的 DOM,需使用 nextTick())
await nextTick()
- onBeforeUnmount (此时组件实例依然还保有全部的功能)
- onUnmounted( 组件卸载完成,用于手动清理一些副作用,例如计时器、DOM 事件监听器、与服务器的连接、自定义事件等)
- onActivated (被
<KeepAlive>
包裹的组件,onActivated 会替代 onMounted, 在首次挂载以及每次从缓存中被重新插入时调用) - onDeactivated (被
<KeepAlive>
包裹的组件,onDeactivated 会替代 onUnmounted, 在被卸载以及每次被移入缓存中时调用)
vue3 自定义 v-model
<!-- 组合式 API vue3.4+ -->
<script setup>
const model = defineModel()
</script>
<template>
<input v-model="model">
</template>
v-model 带参数
<!-- 组合式 API vue3.4+ -->
<script setup>
const title = defineModel('title')
</script>
<template>
<input type="text" v-model="title" />
</template>
父组件
<MyComponent v-model:title="bookTitle" />
vue3 实战
-
vue3【实战】可撤销重做的 input 输入框-CSDN博客
https://blog.csdn.net/weixin_41192489/article/details/139418350 -
vue3 【实战】封装 “心跳“ 组件-CSDN博客
https://blog.csdn.net/weixin_41192489/article/details/139478609 -
Vue3 【实战】封装 useLocation-CSDN博客
https://blog.csdn.net/weixin_41192489/article/details/139486731
React
为什么要使用 Hooks?
- Hooks 能完善函数组件的能力
- Hooks 能更好地实现组件逻辑复用 (class组件不易拆解,不易测试,逻辑混乱)
Hook 实现组件逻辑复用的好处
- 完全符合 Hooks 原有规则,易理解记忆
- 变量作用域明确
- 不会产生组件嵌套
Hooks 模拟组件生命周期
- 模拟 componentDidMount,useEffect 依赖 []
- 模拟 componentDidUpdate,useEffect 无依赖,或者依赖 [a, b]
- 模拟 componentWillUnMount,useEffect 中返回一个函数
ajax 应该放在哪个生命周期?
- 【可能过时】类组件 componentDidMount
- 函数组件 useEffect 依赖 []
渲染列表,为何使用 key
- 同 Vue 。必须用 key,且不能是 index和随机数
- diff 算法中通过 tag 和 key 来判断,是否是同一节点
- 减少渲染次数,提升渲染性能
函数组件和 class 组件区别
- 函数组件是纯函数,输入 props,输出JSX
- 函数组件没有实例,没有生命周期,没有 state
- 函数组件不能扩展其他方法
何时使用异步组件
- 加载大组件
- 路由懒加载
多个组件有公共逻辑,如何抽离
- 函数组件 —— 自定义 Hook
- 【可能过时】class 组件 —— 高阶组件 HOC
- 【可能过时】class 组件 —— Render Props
React 中组件如何通信
- 父子组件 props 传数据/函数
- 兄弟组件—— 状态提升
- useContext
- moxb
- redux
- 自定义事件
React 性能优化
- 渲染列表时加 key
- 及时销毁自定义事件、DOM 事件
- 合理使用异步组件
- 使用 SSR
- webpack 中使用 production,打包时自动删掉调试代码
- 前端通用的性能优化,如图片懒加载
- 【class组件】减少函数 bind this 的次数
- 【class组件】合理使用 SCU Purecomponent和 memo
- 【class组件】合理使用 Immutable.js
React 和 Vue 的相同点和不同点
相同点:
- 都支持组件化
- 都是数据驱动视图
- 都使用 vdom 操作 DOM
不同点:
- React 使用 JSX拥抱 JS,Vue 使用模板拥抱 html
- React 函数式编程,Vue 声明式编程
- React 更多需要自力更生,Vue 把想要的都给你
React 函数组件 和 Vue 函数组件的区别
- Vue 函数组件没有实例和生命周期,比较简单
- React 函数组件 +Hooks 可以实现完备的功能
- Vue Composition API不能用于 Vue 函数组件
对比 Vue3 Composition API 和 React Hooks
- Vue3 Composition API 有组件实例
- React Hooks 没有组件实例,不能在 for if 中使用
【可能过时】什么是受控组件 ?
- 表单的值,受 state 控制
- 需要自行监听 onChange,更新 state
【可能过时】shouldcomponentUpdate 用途
- 性能优化
- 配合“不可变值”一起使用,否则会出错
框架原理
设计模式 —— MVVM
- M —— Model 模型,即数据
- V —— View 视图,即DOM渲染
- VM —— ViewModel 视图模型,用于实现Model和View的通信,即数据改变驱动视图渲染,监听视图事件修改数据
如何理解“数据驱动视图”?
- jQuery 时代需要手动修改 DOM
- Vue React 数据驱动视图,只需修改数据即可触发视图更新
- 解放 DOM 操作,让开发人员更加关注数据和业务
vue2 原理的三大核心
1. 响应式
核心 API 是 Object.defineProperty
Object.defineProperty 的缺点
- 深度监听,需要递归到底,一次性计算量大
- 无法监听属性的新增和删除,这会导致以下操作无响应式:
- 对象新增属性
- 对象删除属性
- 通过数组下标修改数组元素的值
- 修改数组的长度
为了弥补以上操作无响应式的缺陷,vue 补充了 set 和 delete 方法。
$set 的响应式原理
- 对于数组,$set 的参数为
数组、数组下标、新的值
,通过调用被 vue 改造过的添加了视图更新的 splice 方法实现响应式 - 对于对象,$set 的参数为
对象、新的属性、新增的属性的值
,通过对新增属性添加深度监听实现响应式
深度监听的实现
- 深层对象属性的监听,通过递归遍历深层对象的属性实现
- 深层数组的监听,通过变更数组原型(为所有改变数组的 api 中加入更新视图),再递归遍历深层数组实现。
Vue 如何监听数组变化
- 重新定义原型,重写 push pop 等数组方法,实现监听
- Proxy 可以原生支持监听数组变化,在vue3 中已使用,但存在兼容性问题,版本比较老的浏览器无法使用。
描述组件渲染和更新的过程(需画图讲解)
【同考题】请描述响应式原理
- 初次渲染
1. 将模板编译为 render 函数 ( webpack 中使用的 `vue-loader` 插件在开发环境启动项目时会完成编译)
2. 触发响应式,监听 data 属性触发 getter 和 setter 方法 (主要是getter 方法)
3. 执行 render 函数,生成 vnode ,执行 patch(elem, vnode) 完成 DOM 渲染
- 更新过程
1. 修改 data,触发 setter 方法
2. 重新执行 render 函数,生成 newVnode
3. 执行 patch(vnode,newVnode) 更新发生变化的 DOM 节点
- 异步渲染
并不是每一点 data 的改变都会立马触发视图更新, 而是会汇总 data 的修改,再一次性更新视图,这样可以减少 DOM 的操作次数,提高性能。
2. 模板编译
编译过程
- 借助插件
vue-template-compiler
将vue 文件编译成 render 函数 - 执行 render 函数,返回 vnode
- 基于 vnode 执行 patch 和 diff ,完成 DOM 渲染
3. 虚拟节点 vDom
即用 JS 模拟 DOM 结构,计算出最小的变更,再更新 DOM,因为 JS 的执行速度比DOM 操作快得多!
- 通过 h 函数生成 vnode
- 通过 patch 函数渲染 Dom
diff 算法
用于计算出 vDom 的最小变更,时间复杂度降为 O(n)
从 DOM 树的根节点开始
- 只比较同一层级,不跨级比较
- tag 不相同,则直接删掉重建,不再深度比较,依次执行 removeVnodes 和 addVnodes
- tag 和 key,两者都相同,则认为是相同节点,不再深度比较
- tag 相同但 key 不同时,执行 updateChildren
Vue3 与 Vue2 diff 算法的区别
- Vue2 的 updateChildren 是双端比较,Vue3 的 updateChildren 增加了“最长递增子序列” (更快 )
- Vue3 增加了 patchFlag、静态提升、函数缓存等
Vue2、Vue3、React 三者的diff 算法的区别
- Vue2 双端比较
- Vue3 最长递增子序列
- React 仅右移
Vue3 如何实现响应式
vue3 使用 Proxy 实现响应式
Proxy 的优势
与 vue2 的 Object.defineProperty 相比
- 性能更好 (在访问属性时触发监听,若未访问,则不会监听)
- 可监听属性的新增和删除
- 可监听数组的变化
Proxy 的缺点
- 无法兼容所有浏览器
- 无法 polyfill
Vue React 为何循环时必须使用 key
diff 算法会根据 key 判断元素是否要删除
- 匹配了 key,则只移动元素-性能较好
- 未匹配 key,则删除重建-性能较差
用 vnode 描述一个 DOM 结构
- 每个html 标签都是一个对象 {}
- tag 属性的值是一个字符串,内容为标签名
- props 属性的值为 一个对象,key 为标签属性名,value 为标签属性值
- children 属性的值为一个数组,内容为其内部标签的 vnode 描述
根据 JSX / Vue 模板写出 render 函数 / VNode
https://blog.csdn.net/weixin_41192489/article/details/139414314
React 合成事件机制
react 中的事件,不是原生事件(vue 中是原生事件),而是SyntheticEvent 合成事件。
为什么要用合成事件机制 ?
- 更好的兼容性和跨平台(自定义封装的合成事件对象,更方便添加兼容性和跨平台的相关代码)
- 统一挂载到 document 或 id 为root 的根节点 (从 react 17 开始是 root , 利于多个 React 版本并存,例如微前端。),可以减少内存消耗,避免频繁解绑
- 方便事件的统一管理(如事务机制)
React 组件渲染过程
- 通过 props ,state 初始化变量
- 通过 render() 函数生成虚拟节点 vnode
- 通过 patch(elem, vnode) 函数(不一定叫 patch,具体可能是其他名字,功能相同)渲染页面
React 组件更新过程
- 通过 setState(newState) 修改响应式变量,生成 dirtyComponents (可能有子组件)
- 通过 render() 函数生成虚拟节点 vnode
- 通过 patch(elem, vnode) 函数(不一定叫 patch,具体可能是其他名字,功能相同)渲染页面
网络通信
- 前端必备基础【网络通信】(2024最新版)含网络通信过程、网络协议、网络请求、同源策略、跨域、登录验证,输入URL到页面展示的完整过程等
https://blog.csdn.net/weixin_41192489/article/details/140765745
网络通信过程
- TCP 三次握手建立连接
- HTTP 无状态传输数据
- TCP 四次挥手断开连接
HTTP
HTTP 状态码
-
1xx 服务器收到请求
-
2xx 请求成功
- 200 成功(不一定访问了服务器,也可能是命中了浏览器缓存)
-
3xx 重定向
-
301 永久重定向
-
302 临时重定向
-
304 资源未被修改
-
-
4xx 客户端错误
- 403 没有权限
- 404 资源未找到
-
5xx 服务端错误
- 500 服务器错误
- 504 网关超时
HTTP 方法
- get 获取数据
- post 新建数据
- patch/put 更新数据
- delete 删除数据
Http 和 WebSocket 的区别
对比项 | Http | WebSocket |
---|---|---|
连接类型 | 无状态的短连接 | 长连接 |
有无状态 | 无状态 | 有状态 |
请求发起 | 仅客户端 | 客户端和服务端都可以 |
跨域限制 | 有 | 无 |
几次握手 | 3 | 1 |
使用场景 | 从服务器获取数据 向服务器提交数据 | 消息通知,直播间讨论区,聊天室,协同编辑 |
协议名 | http, https | ws , wss |
WebSocket 与 HTTP 长轮询 的区别
- HTTP 长轮询为客户端发起请求,服务端阻塞,不会立即返回(需处理 timeout,即 timeout 之后重新发请求)
- WebSocket 中客户端 和 服务端 都可以发起请求
GET 和 POST 的区别
对比项 | GET | POST |
---|---|---|
功能 | 查询数据 | 提交数据 |
参数传递 | 拼接在 url 上 | 请求的 body 中 |
参数限制 | 有长度限制 | 无限制 |
参数数据类型 | 仅支持ASCII字符 | 无限制 |
参数编码方式 | 仅支持url编码 | 无限制 |
参数的缓存 | 会被完整保留在浏览器历史记录里 | 不会保留 |
安全 | 不能传递敏感信息 | 可防止 CSRF 攻击 |
浏览器回退时 | 无害 | 会再次提交请求 |
浏览器缓存 | 会被缓存 | 默认不会,除非手动设置 |
RestfuI API 风格
- 传统 API设计: 把每个 url 当做一个功能
- Restfu API设计: 把每个 url 当做一个唯一的资源
- 不使用 url 参数
- 请求方法对应固定的数据操作
HTTPS
http 和 https 的区别
- http 是明文传输,敏感信息容易在传输过程中被劫持
- https = http+加密,劫持了也无法解密
https 的加密方式
对称加密 + 非对称加密
访客身份校验
方案1:cookie + session
Cookie
- 用于服务器识别访客身份
- 不能超过 4kb
- 不可跨域共享传递 cookie (主域名相同时,如 www.baidu.com 和 image.baidu.com,设置 cookie domain 为主域名,可以共享)
现代浏览器默认禁止网页中的第三方 JS 设置 cookie,用于打击第三方广告,保护用户隐私,新增属性 SameSite 来修改此项配置。
SameSite
-
值为 Strict 时,完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。
比如,当前网页有一个 GitHub 链接,用户点击跳转就不会带有 GitHub 的 Cookie,跳转过去总是未登录状态。
-
值为 Lax 时,导航到第三方网址的 Get 请求(链接,预加载请求,GET 表单)可以发送第三方 Cookie
-
值为 None 时,即关闭限制。(必须同时设置Secure属性才能生效)
方案2:JWT(token)
token 和 cookie 的区别
- cookie 是 HTTP 规范,而 token 是自定义传递
- cookie 会默认被浏览器存储,而 token 需自己存储
- cookie 默认有跨域限制,token 默认没有跨域限制
cookie + session 和 JWT 哪种方案更好?
cookie + session 的优点
- 原理简单,易于学习
- 用户信息存储在服务端,可快速封禁某个用户
cookie + session 的缺点
- 占用服务端内存,硬件成本高
- 多进程,多服务器时,不好同步 – 需使用第三方缓存,如 redis
- 默认有跨域限制
JWT 的优点
- 不占用服务端内存
- 多进程、多服务器 不受影响
- 没有跨域限制
JWT 的缺点
- 用户信息存储在客户端,无法快速封禁某用户
- 万一服务端秘钥被泄漏,则用户信息全部丢失
- token 体积一般大于 cookie,会增加请求的数据量
综上
- 如有严格管理用户信息的需求 (保密、快速封禁) 推荐 Session
- 如没有特殊要求,则使用 JWT(如创业初期的网站)
如何实现 SSO 单点登录 ?
- 主域名相同时,可通过设置 cookie domain 为主域名,实现 cookie 共享来实现单点登录
- 主域名不同时,需使用 SSO 技术方案,如第三方认证系统,OAuth 2.0
同源策略
protocol(协议)、domain(域名)、port(端口)三者都相同才为同源,否则就是跨域
js 不能跨域访问 cookie、LocalStorage、SessionStorage,不能跨域操作DOM,不能跨域发起 ajax 请求
跨域的方法
- CORS 跨域资源共享(服务端添加允许跨域的配置)
- jsonp (利用 script 标签没有跨域限制实现)
- 仅支持get方法,易遭受XSS攻击
- WebSocket
- nginx 代理 (实质和CORS跨域原理一样,需要服务端添加允许跨域的配置)
哪些 html 标签能跨域 ?
<a>
标签的href属性可以实现跨域链接,但是只能用于GET请求
<a href="http://baidu.com">跨域链接</a>
<img>
标签的src属性可以加载跨域图片
<img src="http://**.jpg" alt="跨域图片">
<link>
标签的href属性可以加载跨域样式表。
<link rel="stylesheet" href="http://**.cn/styles.css">
<script>
标签的src属性可以加载跨域脚本文件,常用于JSONP跨域请求。
<script src="http://**.cn/api.js"></script>
以上标签和属性只是在特定情况下可以用于跨域请求,具体是否允许跨域请求还要看服务器端是否设置了相应的CORS(跨域资源共享)策略。如果服务器没有设置CORS策略,浏览器会阻止跨域请求。
解释 jsonp 的原理,为何它不是真正的 ajax ?
-
jsonp 的原理:借助 script 标签没有同源策略限制的特点,向跨域的目标服务器加载需要的数据。
-
ajax 是通过 XMLHttpRequest 实现, jsonp 并没有用到 XMLHttpRequest
网络安全
XSS
Cross Site Script 跨站脚本攻击
为和CSS(层叠样式表)区分,简称为XSS
原理:攻击者在web页面中插入一些恶意的script
代码。当用户浏览该页面的时候,嵌套在该页面的代码就会执行,从而达到攻击用户的目的。
范例:攻击者在发布的博客中插入一段恶意的script
代码,当用户浏览该博客时,该页面的恶意script
代码被执行,将用户的cookie 等敏感信息传给攻击者的服务器,造成用户信息泄露。
预防
前端和后端都对页面中的特殊字符进行转义,如 <
变为 <
,>
变为 >
const newStr = str.replaceAll('<', '<').replaceAll('>', '>')
相关插件
https://www.npmjs.com/package/xss
用于对用户输入的内容进行过滤,以避免遭受 XSS 攻击
CSRF ( 或简写为 XSRF)
Cross Site Request Forgery 跨站请求伪造
原理:攻击者通过诱导受害者点击打开第三方网站,获取到受害者访问被攻击网站的凭证,冒充受害者在被攻击网站上执行操作。
详细过程
- 用户登录了 A 网站,有了 cookie
- 黑客诱导用户到 B 网站,并发起 A 网站的请求
- A 网站的 API发现有 cookie,认为是用户自己操作的
范例:你正在购物,看中了id为100的商品,付费接口为 xxx.com/pay?id=100 ,这时攻击者向你发了一封邮件,邮件标题很吸引人。当你点开查看邮件时,点击到了邮件正文隐藏的图片,就帮攻击者购买了 id 为 200 的商品。
预防
- 使用 post 接口
- 严格的跨域请求限制,如判断 referrer(请求来源 )
- 为 cookie 设置 SameSite,禁止跨域传递 cookie
- 关键接口增加验证,例如密码、短信验证码、指纹等
点击劫持
Click Jacking
诱导界面上蒙一个透明的iframe,诱导用户点击
预防
让 iframe 不能跨域加载
DDoS
Distribute denial-of-service 分布式拒绝服务
分布式的、大规模的流量访问,使服务器瘫痪
预防
软件层不好做,需硬件预防(如阿里云 WAF)
SQL 注入
黑客提交内容时写入 SQL语句,破坏数据库
预防
处理输入的内容,替换特殊字符
性能优化
H5 优化手段
https://blog.csdn.net/weixin_41192489/article/details/141130671
前端性能优化
https://blog.csdn.net/weixin_41192489/article/details/136497854
web 性能提升
https://blog.csdn.net/weixin_41192489/article/details/126127108
首屏优化
-
路由懒加载
通过路由拆分,优先保证首页加载,适用于SPA (单页面应用),不适用于MPA(多页面应用)
-
服务端渲染 SSR
前后端分离渲染页面过程复杂(至少需三步:1. 加载html,js等资源 2. http请求获取数据 3.渲染页面 ),SSR渲染页面过程简单(在服务端已渲染好页面,直接加载 html 即可),所以性能好( 纯H5页面,SSR 是性能优化的最佳方案)
-
App 预取
如果 H5 在 App WebView 中展示,可使用 App 预取,如用户访问列表页时,App 预加载文章首屏内容,用户进入 H5 页,直接从 App 中获取内容,瞬间展示首屏
-
分页
针对列表页,默认只展示第一页内容,上划加载更多
-
图片懒加载
针对详情页,默认只展示文本内容,然后触发图片懒加载,注意:提前设置图片尺寸,尽量只重绘不重排
-
Hybrid
webpack
【必考】webpack 优化产出代码
- 小图片 base64 编码,减少网络请求
- bundle 加 hash ,充分利用缓存
- 懒加载
- 提取公共代码
- 使用 CDN 加速
- IgnorePlugin 避免引入无用模块
- 使用 production 模式(会自动开启代码压缩,启动 Tree-Shaking,删掉调试代码)
- Scope Hosting(核心原理:合并打包后的函数,使作用域更少,执行更快。)
【必考】webpack 优化构建速度
可用于生产环境
- 优化 babel-loader
- IgnorePlugin(减少打包内容提升打包速度,也缩小了包的体积)
- noParse (减少打包内容提升打包速度,但没有缩小包的体积)
- happyPack 多进程打包
- ParallelUglifyPlugin 多进程压缩 JS
不可用于生产环境
- 自动刷新
- 热更新
- DllPlugin 动态链接库插件(减少打包内容,提升打包速度)
前端为何要进行打包和构建 ?
代码层面
- 体积更小(Tree-Shaking、压缩、合并),加载更快
- 编译高级语言或语法(TS,ES6+,模块化,scss)
- 兼容性和错误检查(Polyfill、postcss、eslint)
前端工程层面
- 统一、高效的开发环境
- 统一的构建流程和产出标准
- 集成公司构建规范(提测、上线等)
babel 和 webpack 的区别
- babel 是 JS 新语法编译工具,不关心模块化
- webpack 是打包构建工具,是多个loader 和 plugin 的集合
为何 Proxy 不能被 Polyfill ?
因为 Proxy 的功能无法用 Object.defineProperty 模拟
拓展知识:
- Class 可以用 function 模拟
- Promise 可以用 callback 来模拟
loader 和 plugin 的区别
- loader 是模块转换器,如less >css
- plugin 是扩展插件,如 HtmlWebpackPlugin
常用的 loader 有哪些?
loader 的执行顺序是:从后往前
- babel-loader 编译 ES6
- css-loader 处理css中的 @import 和 url()
- postcss-loader 提升 css 兼容性
- less-loader 将 Less 文件编译为 CSS
- sass-loader 将 Sass/SCSS 文件编译为 CSS
- style-loader 把 CSS 插入到 DOM 中
- remark-loader 加载 markdown
- html-loader 将HTML 导出为字符串
- file-loader 处理图片等文件
- vue-loader 编译vue文件
更多见 https://www.webpackjs.com/loaders/
常用的 plugin 有哪些?
- HtmlWebpackPlugin 创建HTML 文件
- DllPlugin 动态链接库,可减少打包内容,提升打包速度
- IgnorePlugin 避免引入无用模块 (使用范例:只引入 moment 库的中文模块)
- EslintWebpackPlugin 使用
eslint
来查找和修复 JavaScript 代码中的问题
更多见 https://www.webpackjs.com/plugins/
怎样实现跨域访问?
可通过 devServer 中的 proxy 配置实现
为什么要抽离公共代码?
- 避免公共代码在每个页面中都引入,增加了包的体积
- 避免第三方模块(通常比较大)每次都被重新打包,页面都需要重新加载更新
- 会产生 chunks
怎样实现懒加载?
使用 import ( 路径 ) 的语法即可(会产生 chunks)
babel-polyfill 和 babel-runtime 的区别
- babel-polyfill 会污染全局
- babel-runtime 不会污染全局
- 产出第三方 lib 要用 babel-runtime
IgnorePlugin 和 noParse 的区别
- IgnorePlugin 直接不引入,代码中没有
- noParse 引入,但不打包
module chunk bundle 的区别
- module-各个源码文件,webpack 中一切皆模块
- chunk- 多模块合并成的,如 entry import() splitChunk
- bundle-最终的输出文件
Vite
生产环境中使用 rollup 打包,并不会快很多
开发环境下启动非常快的原因
因为 vite 直接使用 ES6 Module 启动项目,而无需像 webpack 那样先将代码打包成ES5再启动,所以启动非常快。
使用 ES6 Module 运行项目的原理:
<!-- import导入 -->
<script type="module">
import add from "./src/add.js";
add(10, 20);
</script>
<!-- 外链 -->
<script type="module" src="./src/index.js"></script>
<!-- 远程引用 -->
<script type="module">
import { createStore } from "https://unpkg.com/redux@latest/es/redux.mjs";
console.log("createstore", createstore);
</script>
<!-- 动态引入:在点击按钮时,才引入 -->
<script type="module">
document.getElementById('btn1').addEventListener('click', async () => {
const add = await import('./src/add.js')
// 用 export default 导出的,需用 .default 使用!
const res = add.default(1, 2)
console.log('add res', res)
})
document.getElementById('btn2').addEventListener('click', async () => {
const { add, multi } = await import('./src/math.js')
console.log('add res', add(10, 20))
console.log('multi res', multi(10, 20))
})
</script>
实战经验
一键换肤
- 动态修改全局CSS变量
- 切换主题CSS文件
- 切换顶级CSS类名
使用 Vue 过程中遇到过哪些坑 ?
- 内存泄漏(未清除定时器、自定义事件、全局事件等)
- vue2 中给对象新增属性、删除属性,直接给数组下标赋值,页面没有响应式更新(应使用 $set $delete 操作)
- 刷新页面,vuex内的数据丢失(需对vuex添加持久化处理)
- 路由切换时,滚动条默认滚动到顶部(如在列表的第二页,点击进入详情后返回,列表恢复为第一页,且滚动到页面的顶部)
解决方案:在列表页缓存数据和 scrolTop 值,当再次返回列表页时,渲染组件,执行 scrolTo(xx),终极方案: MPA + App WebView 。
使用 React 过程中遇到过哪些坑 ?
-
自定义组件的名称首字母要大写 ( vue 中还支持小写字母 - 格式 )
-
JS 关键字的冲突
-
JSX 的数据类型
第一行:{} 中为动态数据,传入的数字 1 和 布尔值 true
第二行:“” 内为字符串,传入字符串 "1"和字符串 “true” -
setState 是异步更新的
如何统一监听 Vue 组件报错
- errorCaptured 监听下级组件错误,返回 false 阻止向上传播
- errorHandler 监听全局 Vue 组件的错误
- window.onerror 监听其他 JS 错误,如异步,不会监听 try catch 已捕获的错误
拓展:Promise 处理的 catch 捕获的错误,需要用 onunhandledrejection 监听
window.onerror
可全局监听所有 JS 错误(try catch 已捕获的错误除外),但它是 JS 级别的,识别不了 Vue 组件信息,适用于捕捉一些 Vue 监听不到的错误
或
errorCaptured 生命周期
监听所有下级组件的错误,返回 false 会阻止向上传播
errorHandler 配置
Vue 全局错误监听,所有组件错误都会汇总到这里,但 errorCaptured 返回 false,不会传播到这里
异步错误
异步回调里的错误,errorHandler 监听不到,需要使用 window.onerror
Vue 或 React 封装一个“心跳”组件组件每隔 1s 打印 hello
import { useEffect } from "react";
export default function Father() {
useEffect(() => {
let timer = 0;
function fn() {
console.log("hello");
timer = setTimeout(fn, 1000);
}
timer = setTimeout(fn, 1000);
return () => clearTimeout(timer);
});
return (
<div>
<p>心跳</p>
</div>
);
}
- 定时器优先用 setTimeout 实现 (setInterval 在某些极端情况下,如程序逻辑比较耗时等,会遇到问题)
- 组件销毁时,一定要清除定时器!
代码管理
git 常用命令
https://blog.csdn.net/weixin_41192489/article/details/136470311
如何做 Code-review(代码走查),要考虑哪些内容
检查的时间:
- 合并代码前,通过代码 diff 进行 Code review
- 每周例行-次集体 Code review
检查的方式:
- 架构师/前端组长检查
- 前端同事互相检查
检查的内容:
- 是否和现有的功能重复 ?
- 代码规范(eslint 不能全检查,如变量命名、代码语义)
- 重复的代码要抽离、复用
- 组件设计是否合理 ?
- 单个函数内容过长,需要拆分
- 算法复杂度是否可用?是否可继续优化
- 是否有安全漏洞 ?
- 是否具有扩展性 ? (不用为了扩展而扩展,不封闭即可)
- 是否有完善的单元测试 ?
检查的后续:
- 每次 Code review 的问题要记录下
- 归纳整理,形成自己的代码规范体系
- 新加入的成员要提前学习,提前规避
其他
前端技术负责人的主要职责是什么?
目标:按时高质量的完成项目的交付上线,并保障项目上线后安全稳定地运行。
职责:
-
把控需求
参与需求评审,认真审阅需求的详细内容,给出评审意见,提出问题
参与UI 设计图的评审,提出自己的意见和问题
需求和 UI 设计图评审完之后,给出开发的排期。(不仅仅要考虑开发时间,还有内部测试、单元测试的时间,以及考虑一些延期的风险,多加几天的缓冲期。)
后续有新需求时,积极沟通,重新评估,争取延长项目开发周期。 -
技术方案设计
编写设计文档:核心数据结构的设计,核心流程的设计,核心功能模块的组织和实现,服务端、客户端的接口格式评审设计文档(参与对接的,如后端开发需一起参与评审):有没有不合理、隐患、或者和别人开发重复的地方。
-
开发
写通用能力,核心功能,底层逻辑的代码,其他交给成员 -
监督代码质量
- 制定代码规范
- 定期组织代码审核
- CI 时使用自动化单元测试
-
跟踪进度
- 每天都组织 10 分钟站会,收集当前的进度、风险和问题。如有延期风险,要及时汇报。
- 还要关心上下游的进度,如上游的 UI 设计图是否延期
-
稳定安全的运行
- 上线之后,实时把控项目运行状态,是否稳定、安全的运行。遇到问题,第一时间报警。(项目中要增加各种统计和监控功能,例如流量统计、性能统计、错误监控,还有及时报警的机制。)
如何做技术选型 ?
技术选型的核心思想
适合自己的,就是最好的!
技术选型的内容
- 前端框架 (Vue React )
- 语言(Javascript 或 Typescript ,CSS 或 SCSS )
- 其他(构建工具、CI/CD 等)
技术选型的依据
- 社区是否足够成熟
- 公司是否已有经验积累
- 全面考虑各种成本
- 团队成员的学习成本
- 团队成员的管理成本(如用 TS 遍地 any 怎么办 )
- 项目的运维成本
你觉得自己还有哪些不足之处?
- 范围限定在技术方面
- 非核心技术栈
- 容易弥补的,后面才能“翻身”
- 反转话题
话术模板:
- 我觉得自己在 xxx 方面存在不足
- 但我已经意识到,并开始学习 xxx
- 我估计会在 xxx 时间把这块给补齐
参考范例:
“ 我对某某技术的使用还不够熟练,但是,我正在通过学习** 来弥补这个不足,现在已经达成了怎样的效果,过一段时间就会学完,”
前端避免出现bug的方法
- 开发过程中,严格遵守开发规范开发,逻辑不易理解的代码一定要写详细的注释
- 维护已有代码时,要非常小心,不轻易注释/删除已有代码,需理清楚原代码逻辑后进行修改,新增功能最好定义新的变量和方法进行处理,避免对已有功能代码的修改引发已有功能出现bug。
- 开发过程中,对不太确定的开发/解决方案,需花时间搞清楚再开发,自己弄不明白,需和同事交流请教,还无法解决需及时向上级领导汇报,积极寻求各方的帮助,最终探讨出一个可行性的方案。
- 所有开发完成后,开发人员要将本开发周期内所有的功能复测一次
从 0 搭建一个开发环境,需要考虑哪些方面?
-
代码仓库(在哪存放管理项目代码,使用公网还是搭建公司内部仓库)
-
技术选型:选用哪种框架 ? Vue/React/uni-app ,选用哪种 UI 库,是否使用 TS
-
代码目录规范:路由配置文件、公共组件函数文件、页面路径等
-
打包构建 webpack/vite 等,做打包优化
-
引入eslint 规范代码语法
-
使用 prettier 格式化代码
-
引入 commit-lint 检查代码中的问题
-
引入 pre-commit,在代码提交前对代码进行检测,限制不规范代码的提交
-
单元测试
-
CI/CD 流程
CI/CD 是持续集成(Continuous Integration,CI)、持续交付(Continuous Delivery,CD)与持续部署(Continuous Deployment,CD)的简称,注意CD对应了两个名词。
详见 https://blog.csdn.net/u011035397/article/details/124076571
-
开发环境:开发人员在哪里开发
-
预发布环境:测试人员在哪里测试
-
开发文档的编写
如果线上出现了 bug ,你该如何处理 ?
- 先回滚(而不是先排查问题 )
- 排查解决问题,测试,重新上线
- 组内复盘(反思为何出现 bug,有什么方法可以避免再次出现 bug)
如何避免单词拼错?
使用 vscode 插件 Code Spell Checker
开发的时间占比?
1/6,如项目整个周期60天,则开发只占10天。
设计模式在前端开发中的应用场景?
- 观察者模式(DOM 事件)
- 发布订阅模式(自定义事件)
- 装饰器模式(Decorator)
- 代理模式(Proxy)
- 迭代器模式(Generator ,for…of)