1. 防抖和节流:
- 防抖: 单位时间内, 频繁触发事件, 只执行最后一次.
- 例如搜索框中频繁输入内容、频繁点击按钮触发某个事件、监听用户缩放浏览器的resize事件
- 节流: 单位时间内, 频繁触发事件, 只执行第一次,
- 例如高频点击事件,新增修改时提交表单,点提交后按钮置灰防止多次点击提交多次
2. js基础数据类型
- 基本数据类型:string(字符串)、number(数字)、boolean(布尔)、null(空)、undefined(未定义)、symbol(符号)、bigint (长整形,处理高精度)
- 引用数据类型:object(对象,除了基本数据类型其他都是对象。数组是对象、函数是对象、正则表达式也是对象)
3.数据类型检测的方式
1. typeof 运算符
console.log(typeof 42); // "number"
console.log(typeof null); // "object"(需注意)
2.instanceof确判断对象的类型,只能判断引用类型不能判断基本数据
2 instanceof Number // false
'str' instanceof String // false
true instanceof Boolean // false
[] instanceof Array // true
{} instanceof Object // true
function(){} instanceof Function // true
3.Object.prototype.toString.call()
4. 专用检测方法
4.call,aply,bind三者有什么区别?
都是改变this指向和函数的调用,call和apply的功能类似,只是传参的方法不同
- call方法传的是一个参数列表
- apply传递的是一个数组
- bind传参后不会立刻执行,会返回一个改变了this指向的函数,这个函数还是可以传参的,bind()()
- call方法的性能要比apply好一些,所以call用的更多一点
const person = {
name: '王五'
};
function greet(age, city) {
console.log(`你好,我是${this.name},今年${age}岁,来自${city}`);
}
greet.apply(person, [30, '上海']);
// 输出:你好,我是李四,今年30岁,来自上海
greet.call(person, 25, '北京');
// 输出:你好,我是张三,今年25岁,来自北京
// 创建一个新函数,this 指向 person
const boundGreet = greet.bind(person, 28);
boundGreet('广州');
// 输出:你好,我是王五,今年28岁,来自广州
5.$nextTick原理
nextTick是vuejs的一个异步执行方法,的核心是利用了如Promise、MutationObserver、setImmediate、setTimeout等原生JavaScript方法来模拟对应的微/宏任务的实现,本质是为了利用JavaScript的这些异步回调任务队列来实现Vue框架中自己的异步回调队列。
$nextTick 的本质是将回调函数延迟到下次 DOM 更新周期之后执行。Vue 通过异步队列和任务调度机制来实现这一功能。
- data改变之后,DOM不会立即渲染
- $nextTick会在DOM渲染之后被触发,以获取最新的DOM节点
在绝大多数情况下,nextTick 是微任务 vue2中浏览器不支持也可能降级为宏任务,vue3里就是微任务
6.原型链
- 原型和原型链设计的主要目的是实现继承,它通过对象之间的原型关联形成一条链式结构,让对象之间可以共享属性和方法。
- 原型链: 当访问一个对象的属性或者方法时,若自身对象没有,JS会沿着prototype向上查找原型对象,直到找到或者到达原型链的终点(null)
- 隐式原型__proto__,每个对象(除null外)都有一个内置的prototype属性,它可以通过__proto__访问,指向了构造函数的原型(prototype)。
- 原型就是一个普通对象,它是为构造函数的实例共享属性和方法;所有实例中引用的原型都是同一个对象
- 使用prototype可以把方法挂在原型上,内存值保存一份
7.闭包
- 形成条件:
- 有一个外部函数,
- 内部函数引用了外部函数的变量,
- 内部函数被外部函数返回并在外部调用
- 作用:
- 创建私有变量(数据封装)
变量
secret是“私有”的,被安全地封装在outer函数内部,外部代码无法直接修改它,只能通过返回的inner方法来间接影响它。这保证了数据的完整性和安全性。
- 创建私有变量(数据封装)
变量
// 条件1:函数嵌套
function outer() {
const secret = '秘密数据';
// 条件2:内部函数引用外部变量
function inner() {
console.log(secret); // 引用外部变量
}
// 条件3:内部函数被返回或在外部使用
return inner;
}
const myClosure = outer();
myClosure(); // 输出: "秘密数据"
解决闭包的内存泄漏,一个闭包不被需要时,可手动解除对他的引用,
例如将持有闭包的变量设为null
ex: myClosure = null
关键概念:可达性
- 从全局作用域出发,可以通过引用链访问到的值,就是“可达的”。
- 如果某个值变得“不可达”,它就会被回收。
- 当一个外部函数执行完毕后,正常情况下,它的整个作用域(包括所有局部变量)都应该变得“不可达”,从而被垃圾回收。但是,如果这个外部函数内部定义的内部函数(闭包)被外部引用,并且这个内部函数使用了外部函数的变量,那么整个这个外部函数的作用域就会被保留下来,无法被回收。
8.强缓存和协商缓存
- 强缓存 Expires有效期,catch-control(no-cache;max-age=3600,缓存1小时)缓存机制
- 协商缓存 Etag 16进制的标志位,Last-modified 最后修改时间
- 区别
- 强缓存(Strong Caching)和协商缓存(Conditional Caching)是浏览器缓存资源的两种核心机制,旨在减少网络请求、提升页面加载速度并降低服务器负载。
- 强制缓存:强缓存允许浏览器在资源未过期时直接使用本地缓存,无需与服务器通信
- 浏览器根据响应头中的
Expires或Cache-Control字段判断资源是否过期。若未过期,直接从本地加载资源,不发送请求
- 浏览器根据响应头中的
- 协商缓存:协商缓存则在强缓存失效后,浏览器和服务器请求,询问资源是否更新,通过服务器验证来决定是否使用缓存。
- 服务器通过比较响应头(如
Last-Modified或ETag)决定资源是否更新:若未更新,返回304 Not Modified,浏览器使用缓存;若更新,返回新资源
- 服务器通过比较响应头(如
9. 不同的iframe间怎么通信
- postmessage:跨域iframe通信
- 发送消息:
// 语法:targetWindow.postMessage(message, targetOrigin)
// 父页面向子 iframe 发送消息
const iframe = document.getElementById('myFrame');
iframe.contentWindow.postMessage(
{
type: 'FROM_PARENT',
data: { message: 'Hello from parent' },
timestamp: Date.now()
},
'https://child-domain.com' // 目标域,建议明确指定
);
// 子 iframe 向父页面发送消息
window.parent.postMessage(
{
type: 'FROM_CHILD',
data: { message: 'Hello from child' },
id: 'unique-message-id'
},
'https://parent-domain.com'
);
- 接收消息:消息监听器 , 根据消息类型处理
// 父页面接收子iframe的消息
window.addEventListener('message', (event) => {
if (event.data.type === 'MSG_FROM_CHILD') {
console.log('子iframe说:', event.data.data);
}
});
// 子iframe接收父窗口消息
window.addEventListener('message', (event) => {
if (event.data.type === 'MSG_FROM_PARENT') {
console.log('父窗口说:', event.data.data);
}
});
2. window.top和window.parent:同源iframe通信
- 子 iframe直接通过window.top和window.parent访问父窗口的变量或者方法
- 父页面访问子 iframe:通过获取到目标iframe实例的contentWindow对象,来访问iframe中的变量、调用iframe中的方法、或者直接操作iframe的dom
//----子 iframe 访问父页面
// 在 iframe 内部
// 访问直接父窗口
const parentData = window.parent.someVariable;
window.parent.parentMethod();
// 访问顶级窗口
const topData = window.top.someVariable;
window.top.topMethod();
//-----**父页面访问子 iframe:**---------
<!-- 父页面 -->
<iframe id="myFrame" src="child.html"></iframe>
<script>
// 获取 iframe 的 window 对象
const frameWindow = document.getElementById('myFrame').contentWindow;
// 调用 iframe 中的方法
frameWindow.childMethod();
// 访问 iframe 中的变量
const childData = frameWindow.childVariable;
// 直接操作 iframe 的 DOM
const frameDoc = frameWindow.document;
frameDoc.getElementById('elementInFrame').style.color = 'red';
3. localstorage和监听storage
// 发送方
localStorage.setItem('message', JSON.stringify({ data: 'Hello!' }));
// 接收方
window.addEventListener('storage', (event) => {
if (event.key === 'message') {
console.log('收到消息:', JSON.parse(event.newValue));
}
});
9. http和https
- 传输信息安全性不同
- http协议:是超文本传输协议,信息是明文传输。数据在传输过程中可能被窃听、篡改
- https协议:是具有安全性的ssl加密传输协议。确保数据传输的安全。
- 连接方式不同
- http协议:http的连接很简单,是无状态的。
- https协议:是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议。
- 端口不同
- http协议:使用的端口是80。
- https协议:使用的端口是443
- 证书申请方式不同
- http协议:免费申请。
- https协议:需要到ca申请证书,需要交费。
10. scss和less的区别
- 定义变量: scss:$color, less:@color
- 混合:
- scss:使用 @mixin 定义,@include 调用
- less:直接定义类,直接调用类
- 作用域:
- scss块级作用域,如果想在局部修改全局变量需要
!global标志可提升为全局变量 - less全局作用域
- scss块级作用域,如果想在局部修改全局变量需要
- 选择建议:
- scss需要复杂功能或者使用现代框架(Vue、React)
- less简单轻量、适合简单项目和老项目
// scss使用 @mixin 定义,@include 调用
@mixin border-radius($radius) {
-webkit-border-radius: $radius;
-moz-border-radius: $radius;
border-radius: $radius;
}
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
.button {
@include border-radius(5px);
@include flex-center;
}
scss:如果想在局部修改全局变量,需要使用 `!global`
$color: red;
.container {
$color: blue !global; // 现在修改的是全局变量
color: $color; // blue
}
.box {
color: $color; // blue
}
LESS (延迟加载/全局作用域):
@color: red;
.box {
color: @color; // 输出 blue!因为变量“延迟加载”,以后定义的为准
}
@color: blue; // 重新定义,覆盖之前的
10.SCSS 和 Sass 的区别
| 特性 | Sass(缩进语法) | SCSS(CSS兼容语法) |
|---|---|---|
| 文件扩展名 | .sass | .scss |
| 语法风格 | 缩进式(无分号、无大括号) | 使用和CSS类似的大括号和分号 |
| 兼容性 | 不兼容原生CSS | 完全兼容CSS |
- 强大的变量系统 - 支持颜色、数值、字符串、列表、映射($primary-color)
- 嵌套结构 - 清晰的层次关系,减少重复代码
- 混合和继承 - 代码复用和模块化
//定义可复用的代码块:
@mixin flex-center { display: flex; justify-content: center; }
.container { @include flex-center; }
//共享样式规则:
.alert { padding: 10px; }
.error { @extend .alert; color: red; }
3. 丰富的函数 - 内置函数 + 自定义函数
@function darken($color, $amount) {
@return darken($color, $amount);
}
.header { background: darken(blue, 10%); }
5. 逻辑控制 - 条件、循环等编程特性
@for $i from 1 through 3 {
.item-#{$i} { width: 100px * $i; }
}
7. 模块化系统 - @use, @forward 管理依赖
11. vue组件通信方式
- 简单父子通信:Props、emit、通过ref直接访问组件暴露出的方法
- 兄弟组件通信:
- 通过父组件中转数据
- eventsbus:事件总线(任意组件间都能通信)
- 跨组件通信
- provide / inject:祖先组件向后代注入数据
- 全局状态管理
- vuex
- pinia
- 其他:
- localStorage/sessionStorage:通过浏览器存储通信(不是响应式的,可监听store的变化)
//------ eventsbus ----------
export const EventBus = new Vue()
//发送事件
EventBus.$emit('message-sent', {text: 'Hello from Component A'})
mounted() {
//接收事件
EventBus.$on('message-sent', this.handleMessage)
},
beforeDestroy() {
//销毁事件
EventBus.$off('message-sent', this.handleMessage)
},
//----- provide / inject --------
<!-- 祖先组件 -->
export default {
provide() {
return {
appName: '我的应用',
user: { name: '张三', role: 'admin' },
reactiveData: this.reactiveData,// 提供响应式数据
updateData: this.updateData// 提供方法
}
},
data() {
return {
reactiveData: { version: '1.0.0' }
}
},
methods: {
updateData(newData) {
this.reactiveData = { ...this.reactiveData, ...newData }
}
}
}
</script>
<!-- 后代组件(任意层级) -->
<script>
export default {
inject: ['appName', 'user', 'reactiveData', 'updateData'],
methods: {
handleUpdate() {
this.updateData({ version: '2.0.0' })
}
},
mounted() {
console.log('应用名称:', this.appName)
console.log('用户信息:', this.user)
}
}
</script>
//---------- localStorage/sessionStorage -------------------
// 组件 A
localStorage.setItem('shared-data', JSON.stringify(data))
// 组件 B
export default {
mounted() {
// 监听 storage 事件
window.addEventListener('storage', this.handleStorageChange)
// 直接读取数据
const data = localStorage.getItem('shared-data')
},
beforeDestroy() {
window.removeEventListener('storage', this.handleStorageChange)
},
methods: {
handleStorageChange(event) {
if (event.key === 'shared-data') {
this.sharedData = JSON.parse(event.newValue)
}
}
}
}
12. vuex
- Vuex是Vue.js应用程序开发的状态管理模式和库。它为Vue应用程序提供了一个集中式的存储机制,用于管理应用程序的所有组件的状态。
- 作用: 组件间共享状态, 状态管理的可维护性, 跟踪状态变化.
- state, getter, mutation(同步), action(异步), module
// Vuex 实现
const store = createStore({
state: {
count: 0
},
mutations: {
SET_COUNT(state, value) {
state.count = value
},
INCREMENT(state) {
state.count++
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit('INCREMENT')
}, 1000)
}
},
getters: {
doubleCount: (state) => state.count * 2
}
})
// 组件中使用
this.$store.commit('INCREMENT') //修改mutations
this.$store.dispatch('incrementAsync') //调用actions
this.$store.getters.doubleCount
13. vuex和pinia的区别
| 特性 | Vuex | Pinia |
|---|---|---|
| 状态定义 | state | state: () => ({}) |
| 计算属性 | getters | getters |
| 同步操作 | mutations | ❌ 无,直接修改 |
| 异步操作 | actions | actions |
| 模块化 | modules + namespaced | 天然模块化 |
- pinia:无mutations和modules(每个store都是独立的),同步和异步都在action中处理,更轻量1kb
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
getters: {
doubleCount: (state) => state.count * 2,
},
actions: { // 同步和异步都在这里
increment() {
this.count++; // 直接修改,无需 commit
},
async incrementAsync() {
setTimeout(() => {
this.increment(); // 直接调用其他 action
}, 1000);
}
}
});
// 在组件中使用
import { useCounterStore } from '@/stores/counter';
const counterStore = useCounterStore();
counterStore.increment(); // 直接调用 action
console.log(counterStore.doubleCount); // 直接访问 getter
14. vuerouter
15. vue插槽
- 默认插槽:父组件中放入子组件标签内的所有内容,都会在默认插槽的位置被渲染。
- 子组件,
- 父组件直接写内容这里是插槽内容
- 具名插槽:当一个组件需要多个插槽时,你可以给
<slot>元素添加一个name属性。- 子组件,
- 父组件<template #header>这里是插槽内容
- 作用域插槽:它允许子组件在插槽中向父组件传递数据,让父组件可以决定如何渲染这些数据。
<!-- 向父组件传递数据 -->
<slot :item="item" :index="index"></slot>
items: [
{ id: 1, name: '苹果', price: 5 },
{ id: 2, name: '香蕉', price: 3 },
{ id: 3, name: '橙子', price: 4 }
]
//父组件使用 - Vue 2
<template>
<child>
<!-- 使用 `slotProps` 来接收所有传递过来的数据 -->
<template v-slot:default="slotProps">
<span class="item-name">{{ slotProps.item.name }}</span>
<span class="item-price">¥{{ slotProps.item.price }}</span>
</template>
</child>
//父组件使用 - Vue 3 语法
<!-- 解构接收 -->
<template #default="{ item, index }">
<div class="item">
<span>{{ index + 1 }}. {{ item.name }}</span>
<span>¥{{ item.price }}</span>
</div>
4. 动态插槽:插槽的名字也可以是动态的 * 子组件, * 父<template v-slot:[tab1]>
16. keep-alive
keep-alive是 Vue 的内置组件,用于缓存不活跃的组件实例,而不是销毁它们。- 在没有
keep-alive的情况下: 问题: 切换标签时,组件会不断销毁和重新创建,导致:- 状态丢失(表单输入、滚动位置等)
- 重复的网络请求
- 性能开销
- 被 keep-alive 包裹的组件生命周期:
首次加载:
beforeCreate → created → beforeMount → mounted → activated
切换离开:
deactivated
再次进入:
activated
组件销毁:
deactivated → beforeDestroy → destroyed
17. vue2和vue3的区别
一、架构与性能优化
1. 响应式系统重写
- 两者都是 Vue 的响应式系统核心,用于实现数据变化 → 视图更新的自动同步
- Vue2的响应式系统基于Object.defineProperty,它通过劫持属性的getter和setter来实现响应式,但存在一些限制,比如无法检测属性添加、删除、遍历等操作,需要对数组进行特殊处理。
- Vue3的Proxy则更强大,可以拦截整个对象,包括各种操作,提供了更好的性能和更全面的响应式支持。
Vue 2: 使用
Object.defineProperty
// Vue 2 响应式原理
Object.defineProperty(obj, key, {
get() { /* 依赖收集 */ },
set(newVal) { /* 触发更新 */ }
});
- 无法检测对象属性的添加/删除
- 对数组的索引修改和长度修改无法追踪
Vue 3: 使用 Proxy
// Vue 3 响应式原理
new Proxy(obj, {
get(target, key) { /* 依赖收集 */ },
set(target, key, value) { /* 触发更新 */ }
});
- 支持对象和数组的全量响应式
- 性能更好,无需递归遍历对象
2. 体积更小
- Vue 3 通过 Tree-shaking 优化,打包体积减少约 41%
- 核心运行时体积从 ~20KB 减少到 ~10KB
二、语法
- vue2使用选项式api, vue3使用组合式apiOptions API vs Composition API)
- Vue 3 -
<script setup>语法糖
三、组件相关变化
1.支持多根节点
- Vue 2: 组件必须单个根元素
- Vue 3: 支持多根节点
2.引入Teleport 组件
<Teleport> 组件的主要作用:
- 解决样式层叠问题 - 将组件移出可能影响其显示的父容器
- 管理 z-index 层级 - 确保重要组件在最上层显示
- 保持逻辑完整性 - 虽然 DOM 位置改变,但组件逻辑关系不变
- 提升用户体验 - 用于模态框、通知、下拉菜单等需要突破布局限制的组件
<template>
<button @click="showModal">打开模态框</button>
<Teleport to="body">
<div v-if="isOpen" class="modal">
<p>这个模态框会渲染到 body 标签下</p>
</div>
</Teleport>
</template>
四、v-if和v-for的优先级
在vue2中v-for的优先级高于v-if,可以放在一起使用,但是不建议这么做,会带来性能上的浪费
在vue3中v-if的优先级高于v-for,一起使用会报错。可以通过在外部添加一个标签,将v-for移到外层
五、生命周期变化
| 阶段 | Vue 2 | Vue 3 (Composition API) | 说明 | * |
|---|---|---|---|---|
| 组件创建前、后 | beforeCreate created | setup() | 组件创建前、后 | |
| 挂载前 | beforeMount | onBeforeMount | DOM 挂载前 | |
| 挂载后 | mounted | onMounted | DOM 挂载后 | |
| 激活 | activated | onActivated | keep-alive 特有 | |
| 停用 | deactivated | onDeactivated | keep-alive 特有 | |
| 更新前 | beforeUpdate | onBeforeUpdate | 数据更新前 | |
| 更新后 | updated | onUpdated | 数据更新后 | |
| 销毁前 | beforeDestroy | onBeforeUnmount | 组件销毁前 | |
| 销毁后 | destroyed | onUnmounted | 组件销毁后 |
activated和deactivated只在被 keep-alive 包裹时有效- 首次加载时:
mounted和activated都会触发,顺序是mounted→activated - 后续切换时:只有
activated和deactivated会触发,普通生命周期不会再次触发
18. 父子组件生命周期顺序
父组件 beforeCreate → created → beforeMount
→ 子组件开始创建:beforeCreate → created → beforeMount → mounted
→ 父组件 mounted
19. vue返回上一页执行的生命周期
1. 不使用 keep-alive(默认情况)
// 从 A 页面跳转到 B 页面
A 组件 beforeDestroy → destroyed
B 组件 beforeCreate → created → beforeMount → mounted
// 从 B 页面返回 A 页面
B 组件 beforeDestroy → destroyed
A 组件 ← 重新创建 beforeCreate → created → beforeMount → mounted
2. 使用 keep-alive 缓存页面!
// 从 A 页面跳转到 B 页面
A 组件 deactivated ← 只是停用,不是销毁!
B 组件 beforeCreate → created → beforeMount → mounted → activated
// 从 B 页面返回 A 页面
B 组件 deactivated
A 组件 activated ← 重新激活,不会重新创建!
20. 宏任务、微任务
- 微任务: Promise.then、MutationObserver、Node 中的 Process.nextTick等
- 宏任务: script、setTimeout、setInterval、Node中的setImmediate、requestAnimationFrame 等
21. 浏览器输入url以后会发生什么
- 判断输入类型,如果是关键字,调用默认搜索引擎查询,如果是url,解析协议域名端口号
- DNS域名解析,浏览器缓存->系统缓存->路由器缓存->运营商DNS服务器缓存->根域名服务器逐级查询
- 建立TCP三次握手,发送->回复->确认回复
- 发送http请求,包含请求头请求体cookie
- 服务器处理响应并返回
- 浏览器渲染页面
- 断开连接
22. BFC
- 块级格式化上下文
- BFC原则: 如果一个元素具有BFC, 那么元素里边的内容不会影响外边的元素
- 如何触发:
- float不为none
- overflow不为visable
- display值为: inline-block,table-cell
- position值为: absolute, fixed
BFC作用:解决折叠问题、浮动元素高度塌陷问题
23.前端展示1w条数据
- 只渲染可视区域,监听浏览器滚动事件, 到底渲染下一步数据
- 时间分片,通过分批次插入DOM,使用
requestAnimationFrame分批渲染,避免阻塞主线程,使用文档片段createDocumentFragment能够有效地减少重排和重绘,提高性能。
1. 分批次渲染
- 将10000个元素分成500批,每批20个
- 避免一次性创建大量DOM导致的长时间阻塞
2. requestAnimationFrame
- 在浏览器下一次重绘前执行回调
- 将任务分割到不同的帧中执行
- 避免长时间占用主线程导致页面卡顿
3. 文档片段(DocumentFragment)
let fragement = document.createDocumentFragment();
// 在内存中操作,不会触发重排重绘
for(...) {
fragement.appendChild(li);
}
// 一次性添加到DOM,只触发一次重排
ul.appendChild(fragement);
const ul = document.getElementById('ul'); // 获取ul容器元素
const totalNum = 10000; // 总共要创建10000个li
const onceNum = 20; // 每次批量创建20个
const page = totalNum/onceNum; // 计算总批次数(500次)
const index = 0; // 起始索引
function loop(curTotal, curIndex) {
if(curTotal <= 0) { // 递归终止条件:没有剩余元素要创建
return false;
}
const pageCount = Math.min(curTotal, onceNum); // 本次要创建的数量
window.requestAnimationFrame(() => { // 在浏览器下一帧渲染时执行
let fragement = document.createDocumentFragment(); // 创建文档片段
for(let i = 0; i < pageCount; i++) {
let li = document.createElement('li');
li.innerText = curIndex + i + ':' + (Math.random() * totalNum); // 创建li内容
fragement.appendChild(li); // 先添加到文档片段
}
ul.appendChild(fragement); // 一次性将文档片段添加到DOM
loop(curTotal - pageCount, curIndex + pageCount); // 递归调用处理剩余元素
})
}
loop(totalNum, index); // 开始执行
24.大文件上传
"对于大文件上传,我采用切片上传 + 断点续传的方案:
- 前端将大文件切割成512KB的切片,使用Web Worker计算文件hash避免阻塞
- 上传前先校验,通过hash检查服务器已存在的切片,实现秒传和断点续传
- 控制并发上传,同时处理3-5个切片请求,平衡速度和服务器压力
- 所有切片上传完成后,通知后端合并文件
- 结合IndexedDB存储切片信息,支持刷新页面后继续上传
- 提供完整的进度反馈和错误恢复机制,提升用户体验
25.dom的diff算法
DOM Diff算法 + Key的作用:
// Diff算法:比较两棵DOM树的差异,最小化更新操作
// 目标:找到最少操作,从旧树变成新树
// 没有Diff算法的情况:
// 每次更新 → 销毁整个DOM → 重新创建整个DOM
// 性能极差,用户体验糟糕
// 有Diff算法的情况:
// 每次更新 → 比较差异 → 只更新变化的部分
// 高性能,保持用户交互状态
- 身份标识:Key帮助Diff算法识别哪些节点是相同的
- 高效复用:避免不必要的DOM销毁和重建
- 状态保持:确保组件状态在更新时正确保持
- 性能优化:减少DOM操作,提升渲染性能
vue2、vue3diff算法区别
- Vue 2 的 diff 算法采用“双端比较”的策略,
- 使用四个指针(旧头、旧尾、新头、新尾)同时从新旧子节点的两端向中间遍历
- 如果两端交叉比较后都没有相同的,则尝试在旧节点中查找与 newStart 具有相同 key 的节点
- Vue 3 的 diff 算法采用“最长递增子序列”的方法来最小化移动次数
- 预处理:从两端开始进行同步,相同的跳过不参与对比,直到遇到第一个不同的节点。
- Vue 3 的 diff 算法遍历新节点,通过寻找旧节点索引序列中的最长递增子序列,确定哪些节点不需要移动,来最小化 DOM 移动操作
26.import和require区别
import 是 ES6 模块规范,在编译阶段静态加载,在代码执行前就确定了模块依赖关系,支持 Tree Shaking(移除未引用代码)和代码分割,利于减小打包体积;仅能置于文件顶部,导入的值是浅拷贝,修改会同步影响源对象,
require 属于 CommonJS 规范,是运行时的函数调用,动态地加载并执行模块,不支持 Tree Shaking,需手动优化,可在代码任意位置,导入的值是深拷贝,修改不影响源对象,
27.git命令
回退命令
- 使用
git reset(本地回滚,不保留提交记录 )--hard:完全删除上次提交(包括代码改动)。--soft:保留代码改动,仅撤销提交记录(修改会进入暂存区)。HEAD~1表示“上一次提交”,HEAD~2表示“上两次提交”,以此类推
- 使用
git revert(生成反向提交,保留历史记录)git revert会创建一个新的提交,内容与上次提交相反(例如删除新增的代码)。- 适用于远程仓库已推送的情况,避免强制推送(
git push --force)的风险。
# 回滚到上一次提交之前(删除上次提交)
git reset --hard HEAD~1
# 如果只想撤销提交但保留代码修改(软回滚)
git reset --soft HEAD~1
# 生成一个反向提交来撤销上次提交
git revert HEAD
经常使用的 git 命令?
git init // 新建 git 代码库
git add // 添加指定文件到暂存区
git rm // 删除工作区文件,并且将这次删除放入暂存区
git commit -m [message] // 提交暂存区到仓库区
git branch // 列出所有分支
git checkout -b [branch] // 新建一个分支,并切换到该分支
git status // 显示有变更文件的状态
`git reset --soft` 来回退但不丢弃之后的改动和提交。
`git reset --hard` 来彻底丢弃之后的改动和提交。
`git revert` 来创建一个新的提交以撤销之前的提交,同时保留历史记录。
28.Axios和promise的关系
- Axios 是基于 Promise 封装的,它利用 Promise 的特性实现异步请求的链式调用和错误处理
- 所有 Axios 请求返回 Promise
- Axios 的
get、post等方法默认返回一个 Promise 对象,因此可以直接使用.then()和.catch()处理响应或错误。 - 也可以使用 async/await 语法,因为 async/await 是基于 Promise 的
29.js 冒泡和捕获方法区别
| 特性 | 事件冒泡 | 事件捕获 |
|---|---|---|
| 传播方向 | 从里到外(子 → 父) | 从外到里(父 → 子) |
| 默认行为 | 默认启用(addEventListener参数为 false) | 需显式启用(参数为 true) |
| 适用场景 | 常用(如委托事件)常规事件处理 | 特殊需求(如提前拦截) |
事件循环面试题
1. 浏览器事件循环
* 2. 宏任务和微任务:
- 微任务: Promise.then、MutationObserver、Node 中的 Process.nextTick等
- 宏任务: script、setTimeout、setInterval、Node中的setImmediate、requestAnimationFrame 等
3. node事件循环,process.nextTick
node跟浏览器类似,都是v8引擎来处理js,事件循环是由libuv实现,
v8引擎
1. v8引擎执行原理
v8引擎是浏览器和node.js的处理js的引擎
2. js引擎(v8)常见的垃圾回收(GC)算法
this指向面试题
- this指向跟定义位置没有关系,跟调用位置有关系,运行时才被绑定
- 变量定义时就已经确定,跟定义位置有关系,跟调用位置没有关系
HTML-CSS面试题
1.什么事seo,为什么seo对一个网站很重要?
2.seo有哪些关键点,你在日常开发中,采取了哪些措施来进行seo?
3.defer和async属性在script标签中有什么作用
4.async、defer的面试回答
5.CSS3新特性
1. 选择器(Selectors):
-
新的属性选择器:
[attr^="value"]:选择属性值以 "value" 开头的元素。[attr$="value"]:选择属性值以 "value" 结尾的元素。[attr*="value"]:选择属性值中包含 "value" 的元素。
-
结构性伪类:
:nth-child(n):选择父元素下的第 n 个子元素。:nth-last-child(n):选择父元素下的倒数第 n 个子元素。:first-of-type:选择父元素下同类型中的第一个子元素。:last-of-type,:nth-of-type(n)等。
2. 背景和边框(Backgrounds and Borders):
- 边框图片:
border-image属性,允许使用图像作为元素的边框。 - 多重背景:允许一个元素设置多个背景图像,使用逗号分隔。
- 圆角边框:
border-radius属性,可以轻松创建圆角效果。 - 盒阴影:
box-shadow属性,为元素添加一个或多个阴影。
3. 文本效果(Text Effects):
- 文本阴影:
text-shadow属性,为文本添加阴影效果。 - 文本溢出:
text-overflow属性,定义当文本溢出包含元素时发生的事情(如显示 "...")。 - 文字换行:
word-wrap和word-break属性,允许对长单词进行换行。
4. 转换、过渡和动画:
-
2D/3D 转换:
transform属性允许您对元素进行旋转 (rotate)、缩放 (scale)、倾斜 (skew) 或平移 (translate)。- 包括 3D 变换功能,如
rotateX,rotateY,translateZ等。
-
过渡:
transition属性,允许 CSS 属性值在一定的时间区间内平滑地过渡。 -
动画:
animation属性和@keyframes规则,允许创建复杂的动画序列。
.transform-2d {
transform: translate(100px, 50px); /* 移动 */
transform: rotate(45deg); /* 旋转 */
transform: scale(1.5); /* 缩放 */
transform: skew(30deg, 20deg); /* 倾斜 */
/* 多重变换 */
transform: translateX(100px) rotate(45deg) scale(1.2);
}
transition: all 0.3s ease-in-out;
5. 其他重要特性(对您列表的补充):
-
布局:
- Flexbox 布局:
display: flex,提供一种更有效的方式来布局、对齐和分配容器内项目之间的空间。 - Grid 布局:
display: grid,创建基于网格的二维布局系统。
- Flexbox 布局:
-
颜色:
- RGBA 和 HSLA:支持 Alpha 通道(透明度)的颜色模式。
-
盒模型:
box-sizing属性,可以改变计算元素宽度和高度的方式(如border-box)。
-
媒体查询:
@media,为不同屏幕尺寸和设备类型应用不同的样式,是响应式设计的核心。
6.为什么在移动端使用@2x、@3x的图片适配移动端
7.怎么画出0.5px边框
*****8.通常采用哪些措施保证网站或者应用在不同浏览器上的兼容性
浏览器渲染面试题
******1.浏览器输入url以后会发生什么?
2.浏览器内核是什么、有哪些常见浏览器内核?
******3.什么是回流、重绘
4.css文件如何被浏览器解析并应用到页面上
跨域访问面试题
****1.什么是同源策略,为什么浏览器会有同源策略
2.什么是正向代理、反向代理
正向代理
反向代理
*****3.描述开发中遇到的跨域问题,及解决方案
****4.如何使用nginx作为解决跨域的一种方法,他的工作原理
*****5.ngnix配置流程
异步编程方案相关面试题
1.Promise相关面试题
****promise是用来处理异步操作的对象
***Promise 的三种状态
// Promise 的三种状态
const promise = new Promise((resolve, reject) => {
// pending(进行中)
// 状态改变后不可逆:
// resolve(value) → fulfilled(已成功)
// reject(reason) → rejected(已失败)
});
Promise 的三种实例方法
// 使用 Promise
myPromise
.then(result => {
console.log('成功:', result);
})
.catch(error => {
console.log('失败:', error);
})
.finally(() => {
console.log('无论成功失败都会执行');
});
****Promise 的静态方法
- Promise.all() - 全部成功
Promise.all([promise1, promise2, promise3])
.then(values => {
console.log('所有都成功:', values); // [1, 2, 3]
})
.catch(error => {
console.log('有一个失败:', error);
});
2. Promise.allSettled() - 全部完成
3. Promise.race() - 竞速
4. Promise.any() - 任意一个成功
****2.async/await,与promise相比的优势和不同
async用于声明一个异步函数
await后面通常跟一个表达式,一般返回一个promise
| 特性 | Promise | async/await |
|---|---|---|
| 代码风格 | 链式调用,函数式 | 同步风格,命令式 |
| 可读性 | 复杂逻辑时嵌套深 | 更接近同步代码,易于理解 |
| 错误处理 | .catch() 方法 | try/catch 块 |
async function async1 () {
console.log('2---async1 start')
await async2() // 这一句会同步执行,返回 Promise ,其中的 `console.log('async2')` 也会同步执行
console.log('6---async1 end') // 上面有 await ,下面就变成了“异步”,类似 cakkback 的功能(微任务)
}
async function async2 () {
console.log('3---async2')
}
console.log('1---script start')
setTimeout(function () { // 异步,宏任务
console.log('8---setTimeout')
}, 0)
async1()
// 初始化promise时,传入的函数会被立即执行
new Promise (function (resolve) { // 返回 Promise 之后,即同步执行完成,then 是异步代码
console.log('4---promise1') // Promise 的函数体会立刻执行
resolve()
}).then (function () { // 异步,微任务
console.log('7---promise2')
})
console.log('5---script end')
// 同步代码执行完之后,屡一下现有的异步未执行的,按照顺序
// 1. async1 函数中 await 后面的内容 —— 微任务
// 2. setTimeout —— 宏任务
// 3. then —— 微任务
//初始化promise时,传入的函数会被立即执行,后面的then就是异步,为微任务
****ES6新特性面试题
webpack相关面试题
分包 SplitChunks webpack.optimize.CommonsChunkPlugin
前端构建速度优化
1.使用高版本 Webpack 和 Nodejs
2.多进程/多实例构建 thread-loader
3.压缩代码
多进程并行压缩
webpack-paraller-uglify-plugin
terser-webpack-plugin开发parallel
mini-css-extract-plugin
4.图片压缩
imagemin
image-webpack-plugin
5.缩小打包作用域
6.提取页面公共资源
使用html-webpack-external-plugin 基础包通过cdn引入,不打入bundle中
使用splitchunksplugin 提取公共脚本, 基础包 页面公共文件分离
7.充分利用缓存,提升二次构建速度
babel-loader
terser-webpack-plugin
cache-loader
8.tree shaking
删除没用的模块
webpack常见的loader
raw-loader: 读取文件内容,返回字符串,不会转码。
file-loader:
url-loader: 读取文件内容,返回base64编码的字符串,不会转码。
source-map-loader: 读取.map文件,返回源码。
image-loader: 读取图片,返回base64编码的图片字符串,不会转码。
json-loader: 读取JSON文件,返回JSON对象。
babel-loader: 用babel转码代码。
css-loader: 用来加载css文件。
sass-loader: 用来加载SASS文件。
ts-loader: 用来加载TypeScript文件。
style-loader: 把css文件插入到html中
postcss-loader: 用来处理css文件,支持css3新特性。
eslint-loader: 用来检查代码中的语法错误。
tslint-loader: 用来检查代码中的语法错误。
vue-loader: 用来加载Vue文件。
webpack常用的plugin
define-plugin: 用来定义环境变量。
ignore-plugin: 用来忽略某些文件。
html-webpack-plugin: 简化HTML文件创建。
uglify-webpack-plugin: 用来压缩js。
mini-css-extract-plugin: 用来提取css文件。
clean-webpack-plugin: 用来清理构建目录。
webpack-bundle-analyzer: 打包后打开一个页面可以查看文件大小。
speed-measure-webpack-plugin: 用来查看构建时间。
Loader和Plugin的区别
1. Loader本质是一个函数,它可以对模块进行预处理,比如将ES6代码转换为ES5代码,
将SASS代码转换为CSS代码,将图片转换为base64编码的图片字符串,将JSON文件转换为JSON对象等等。
2. Plugin本质是一个类,它可以对构建过程进行扩展,比如添加新的功能,webpack运行生命周期中会广播很多实践,插件可以监听这些事件,并执行相应的操作。
3. loader:module.rules配置,类型是数组树,可以配置多个loader
4. plugin:webpack.plugins配置,类型是数组树,可以配置多个plugin
webpack构建流程
1.初始化参数:从配置文件和 shell 语句中读取并且合并参数,得到最终的参数
2.开始编译:初始化Compiler 加载所有配置插件,执行象run 方法,开始编译
3.确定入口:entry 找到所有入口
4.编译模块:调用所有 loader 对模块进行翻译,找出模块依赖的模块,在递归本步骤知道所有入口依赖的文件都经过处理
5.完成模块编译:得到每个模块被翻译后的最终内容以及他们之间的依赖关系
6.输出资源:包含多个模块的 chunk,每个 chunk 转换成单独的文件加入到输出列表中,可以修改输出内容
7.输出完成:根据配置确定输出的路径和文件名,把文件内容写出到文件系统
webpack高效率插件
webpack-dashboard:更好的展示相关包的信息
webpack-bundle-analyzer:打包后打开一个页面可以查看文件大小
webpack-merge:合并webpack配置
speed-measure-webpack-plugin:分析loader和plugin耗时,分析构建过程中的性能瓶颈
HotModuleReplacementPlugin(HMR):模块热替换,当模块更新时,不会重新刷新页面,而是替换掉对应的模块,不会丢失状态。
xss攻击-跨站脚本攻击
- 危害:窃取cookie,劫持流浪,插入广告,植入木马,获取用户信息
- 攻击方式:url参数注入,输入框注入
- 分类:反射型(浏览器提交代码到服务器->服务端将代码传回客户端)、储存型(浏览器提交代码到服务器->将恶意代码储存到数据库)、DOM型(恶意代码仅在客户端执行)
- 预防:
校验(输入进行格式校验)、过滤(过滤特殊标签<script><iframe>,过滤onclick,onerror,onfocus等)、编码转义、限制(输入长度,cookie设置成httponly)
csrf 跨站请求伪造
sec-fetch-site: same-origin
攻击一般发起在第三方网站,而不是被攻击的网站。被攻击的网站无法防止攻击发生。
攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作;而不是直接窃取数据。
整个过程攻击者并不能获取到受害者的登录凭证,仅仅是“冒用”。
跨站请求可以用各种方式:图片URL、超链接、CORS、Form提交等等。部分请求方式可以直接嵌入在第三方论坛、文章中,难以进行追踪。
两个特点:CSRF(通常)发生在第三方域名。CSRF攻击者不能获取到Cookie等信息,只是使用。
性能优化面试题
1.项目架构
1.项目架构思路
2.项目架构实现一: 采用模块化的架构设计
3.项目架构实现一:其他方面的设计
2.项目开发:框架相关优化
3.项目部署:优化手段
要性能优化,需要从项目架构、项目开发、项目部署三个阶段来考虑。
(1)首先是项目架构方面。在正式开发之前,我们应该设计好整个项目的架构,目的是尽量对项目的模块进行解耦,方便多个程序员进行协同开发。解耦的标准可以按照功能或者状态划分。
例如我们的项目中,网络请求是最常使用的功能,所以相关的功能就划分成了单独的模块。在对Axios统一封装的时候,首先是基本的拦截和响应逻辑封装在一个文件中,有些配置项为了方便修改,我们会单独封装成另一个文件,例如自定义的状态码提示文字。然后为了方便阅读和维护,我们会把大的service.js文件拆分成一些处理不同功能的小service文件,比如userService、menuService等,用来划分不同的公共请求。至于每个具体的业务功能页面,我们会定制规范,规定用单独的文件夹包裹,每个页面自己的请求和封装成单独的js文件,和对应的vue代码放到一个文件夹中,确保文件结构清晰。
又例如项目中有一些通用的函数工具,我们会放在utils目录下。比如日期格式化、数字精度处理、嵌套对象展平、数组切割、权限校验等。这些函数不依赖外部状态,他们会在index.js中导出,供其他页面直接使用。
此外webpack、vite等工具也会对代码进行分割、动态导入还有tree shaking,这些都可以提升项目的性能。
还有git分支管理,每个人开发新需求的时候都从master分支拉一个新分支,合并的时候先往develop分支合并进行测试,没问题了再往release分支合并,在迭代结束时会有人专门把代码从release分支合并到master进行上线,然后下一个迭代开始时develop分支又会用master分支重置,这样可以大大减少代码合并的冲突。
项目的打包和部署用jenkins和rancher实现流程自动化,提升效率。
此外我们还会定期做code-review和文档整理,尽早发现并解决问题,减少问题的堆积。
(2)开发过程中的优化:
1. 避免组件不必要的渲染。具体手段包括:
①合理使用v-if和v-show;
②使用key确保组件唯一性,避免不必要的dom刷新;
③使用v-once确保不变的数据只渲染一次;
④合理使用生命周期钩子;
⑤使用import按需加载组件,减少初始加载时间;
⑥合理使用组件缓存动态组件,避免不必要的组件销毁和创建;
⑦有大量数据要渲染时,可以采用虚拟列表+无限滚动的方式来优化性能;
⑧尽量避免回流和重绘,尽量减少dom操作,使用批量更新。
2. 减少不必要的计算,尤其是避免在渲染过程中大量计算。应该把重计算的操作放在适当的位置,比如computed中,它可以缓存计算结果,避免重复计算。也可以放在web workers中,避免阻塞主线程,保持UI流畅。
3. 优化循环和迭代:比如获取数组长度arr.length在循环外边获取,避免在循环中创建新数组和对象;
4. 在频繁触发的事件上(点击、滚动)做好防抖和节流,减少事件处理频率
5. 避免内存泄漏,在组件中定时销毁计时器、事件监听器、闭包等
6. CSS相关优化:
①使用简单的CSS选择器,避免复杂的选择器链
②使用CSS动画,避免js动画
③使用transfrom和opacity处理动画效果,可以GPU加速
7. 图片优化,包括:
①提前用第三方工具对图片进行压缩处理;
②使用一些现代图片格式(webP、AVIF)来减小图片大小;
③使用精灵图,来降低网络开销;
④图片懒加载,只加载可视区域的图片,减少初始加载时间和网络消耗;
8. 服务端渲染(SSR),将完整的html发送到客户端,加快首屏渲染速度,也可以进行SEO优化
9. 使用webpack和vite对代码进行压缩、混淆和拆分(比如使用Terser等工具压缩js,使用其他工具压缩html和css)
10. 第三方包按需引入,例如elementplus等,使用babel或vite配置,按需引入,减少打包体积;
11. 状态下沉:根据虚拟dom的更新特性,将状态下沉到子组件,避免全局或父组件频繁更新
(3)部署过程中的优化:
- CDN的使用和配置,用于加速静态资源,将资源缓存在最近的服务器上
2.首屏加载速度优化,包括:
①将首屏渲染所需的关键CSS内联到html中,减少css阻塞渲染的时间;
②使用async和defer来异步加载JS脚本,避免阻塞渲染;
③懒加载、代码分割,将非关键的代码分离,减少初始加载时间;
④使用SSR技术(服务端渲染)
3.使用http缓存,在客户端缓存静态资源,避免重复请求设置http缓存头。为静态资源设置缓存策略,包括强缓存(需要cache-control和expires,一般缓存js、css文件,在文件更新时生成新的文件名,让客户端下载新的文件)和协商缓存(配置Etag和last-modified,一般用于频繁改变的文件,比如html文件)
- 压缩,包括:
①代码压缩(去掉多余的空格、空行、注释、代码缩短、tree-shaking,可以使用webpack、vite自带的压缩插件)
②图片压缩(一般用其他工具或者后端压缩,不在前端压缩,可以使用svg又小又无损缩放)、③文件压缩(在服务器配置中启用gzip就行,前端拿到.gzip文件会由浏览器自动解压)
1. 减少和优化资源请求:
①减少DNS查询,将多个资源放到同一个域名下,减少DNS查询时间;
②通过异步加载或延迟加载(例如async和defer)减少第三方脚本的影响。
③必须跨域的资源可以用DNS预加载和预解析:
预加载(preload,例如 来预加载关键资源)和预解析(prefetch,例如 来预获取将来可能用到的资源)
4. 性能测量工具(待续):
1.performance
performance,浏览器自带提供,给各种性能做测量工作,performance.now()可高精度时间测量,以毫秒为单位,精确到小数点后五位(微妙),还可以用performance.mark和performance.measure等
页面加载时间测量
先用lightHousec查看当前页加载性能,时间性能,明显感觉那个页面卡用Performance检测哪里有问题,如果大可以拆开不行就分包处理
2.谷歌工具:Performance(性能面板)
"Performance 工具是我们分析运行时性能的首选。比如当用户反馈页面操作卡顿时,我会用 Performance 录制一段操作,重点分析:
- Long Tasks:查找执行时间超过 50ms 的长任务
- Layout Thrashing:检查是否存在频繁的强制同步布局
- Main Thread Bottlenecks:定位 JavaScript 执行或渲染的瓶颈
核心功能:
- 帧率分析:检查是否保持 60fps 流畅度
- 主线程活动:查看 JavaScript 执行、布局、绘制等耗时
- 网络请求时间线:结合资源加载分析性能瓶颈
3.谷歌的light-house工具
核心指标(Core Web Vitals):
- LCP(最大内容绘制):加载性能
- FID(首次输入延迟):交互响应性
- CLS(累积布局偏移):视觉稳定性
面试回答示例:
"Lighthouse 是我们持续监控网站健康度的标准工具。在项目中我们把它集成到 CI/CD 流程中,每次发布前自动检测:
- 性能评分:确保不低于 90 分
- 核心 Web 指标:监控 LCP、FID、CLS 是否达标
- 最佳实践:检查 HTTPS、图片优化等
通过 Lighthouse 的报告,我们系统性地优化了图片懒加载、资源压缩等,让首屏加载时间从 4s 降到 1.8s。"
4.谷歌工具:nextWork
监控所有网络请求的详细信息的工具。
核心分析维度:
- 请求瀑布流:分析请求依赖和并行性
- 资源大小:检查未压缩的资源
- 请求优先级:验证关键请求是否被优先处理
面试回答示例:
"Network 面板是我优化加载性能的基础工具。主要关注:
- 关键请求链:找出阻塞渲染的核心资源
- 资源压缩:检查图片、JS、CSS 是否合理压缩
- 缓存策略:验证静态资源缓存配置是否正确
曾经发现一个 2MB 的未压缩图片,优化后体积减少 80%,显著改善了 LCP 指标。"
分层诊断思路:
"我习惯按加载性能 → 运行时性能 → 综合质量的层次使用不同工具:
-
首先用 Network + Lighthouse 诊断加载阶段问题
- Network 看具体请求细节
- Lighthouse 看整体评分和核心指标
-
然后用 Performance 分析运行时交互性能
- 录制用户操作,分析长任务和渲染瓶颈
-
最后用 Light-house 验收 整体优化效果
- 确保各项指标达到标准"
- 确保各项指标达到标准"
webpack\git相关
xxx1.整理npm、yarn常用的命令以及作用
| npm | yarn | 描述 |
| :------------------------------- | ---------------------------- | ------------------------------ |
| npm install | yarn install | 根据package.json中的依赖包安装 |
| npm install [package] | yarn add [package] | 默认安装开发和生产依赖 |
| npm install --save [package] | yarn add [package] | 默认安装开发和生产依赖 |
| npm install --save-dev [package] | yarn add [package][--dev/-D] | 安装开发依赖 |
| npm rebuild | yarn install --force | 强制重新build |
| npm uninstall [package] | yarn remove [package] | 卸载某个依赖包 |
| npm cache clean | yarn cache clean | 清除缓存 |
| npm update [package] | yarn upgrade | 更新指定包 |
xxx2.说出npm install的安装过程
xxx3.npm、cnpm、yarn、pnpm
- yarn
- cnpm:设置镜像
- pnpm:更高效的包管理工具
xxx4.说说pnpm的原理(软连接、硬链接)和用法
- 软链接(符号链接)
- 保存某个文件的绝对路径或者相对路径
- 类似于快捷方式
- 硬链接
- 是电脑文件系统中的多个文件平等地共享同一个文件存储单元
- 删除一个文件名字后,还可以用其它名字继续访问该文件
- pnpm的node_modules是非扁平化的结构
- 让自己的项目不会随便引入非自己安装的依赖
- 软连接和硬链接结合:node_modules下文件是软连接、指向node_modules下的.pnpm文件中的硬链接,这些硬链接指向测盘中存放的真正的包
- pnpm的使用
| npm命令 | pnpm等价命令 | 描述 |
| ------------------- | ----------------- | -------------------------- |
| npm install | pnpm install | 安装package.json中的依赖包 |
| npm install <pcg> | pnpm add <pcg> | 默认安装开发和生产依赖 |
| npm uninstall <pcg> | pnpm remove <pcg> | 卸载某个依赖包 |
| npm run <cmd> | pnpm <cmd> | 运行某个脚本 |
xxx5.什么是webpack
***6.webpack如何对项目进行打包
- 最终会生成可部署的静态资源文件
***7.什么是loader?webpack的loader是什么作用?
什么是loader?
- loader用来对模块的源代码进行转换,加载文件
- 比如因为webpack 不知道怎么样去加载css文件,所以我们需要用css-loader来加载css文件
- 主要通过配置方式来使用loader来加载,在webpack的配置文件的
module.rules下 - 处理流程:webpack遇到文件→匹配rules规则→使用指定loader处理→输出结果
module: {
rules: [
{
// 告诉webpack匹配以.css结尾的文件
test: /\.css$/,
// use: [
// // 注意顺序,从下往上执行
// { loader: "style-loader" },
// { loader: "css-loader" }
// ]
//简写一: 如果loader只有一个
// loader: "css-loader"
//简写二: 多个loader不需要其他属性时,可以直接写loader字符串形式
// 配置方式一
use: ["style-loader", "css-loader", "postcss-loader"]
// 配置方式二
// use: ["style-loader", "css-loader", {
// loader: "postcss-loader",
// options: {
// postcssOptions: {
// plugins: [
// "autoprefixer"
// ]
// }
// }
// }]
},
{
// 告诉webpack匹配以.css结尾的文件
test: /\.less$/,
// use: [
// // 注意顺序,从下往上执行
// { loader: "style-loader" },
// { loader: "css-loader" },
// { loader: "less-loader" },
// { loader: "postcss-loader" }
// ]
// 简写
use: ["style-loader", "css-loader", "less-loader", "postcss-loader"],
}
]
}
***8. loader和plugin的区别
loader是用于特定的模块类型(css,vue...)进行解析加载plugin 是用于执行更多广泛的任务,比如打包优化,资源管理,环境变量注入等
核心区别:
-
Loader作用:用于特定模块类型的转换,进行加载,进行解析时用,如处理.vue、.css、.png等确定类型的文件, 仅在文件加载转换阶段执行
-
Plugin作用:执行更广泛的任务,包括打包优化、资源管理、环境变量注入等 (执行loader外所有任务,并且贯穿整个生命周期)
-
loader:module.rules配置,类型是数组树,可以配置多个loader
-
plugin:webpack.plugins配置,类型是数组树,可以配置多个plugin
9.常见的loader和plugin
vue-loader: 用来加载Vue文件。
postcss-loader: 用来处理css文件,自动添加浏览器前缀,支持css3新特性。
less-loader: 将less编译为css
sass-loader: 用来解析SASS文件。
css-loader: 用来解析css文件。
style-loader: 将css注入到DOM中
babel-loader: webpack遇到.js文件时,会先用babel-loader进行转译,将ES6+代码(如箭头函数、class)转换为ES5等更兼容的语法
ts-loader: 用来解析TypeScript文件。
eslint-loader: 用来检查代码中的语法错误。
tslint-loader: 用来检查代码中的语法错误。
json-loader: 读取JSON文件,返回JSON对象。
image-loader: 读取图片,返回base64编码的图片字符串,不会转码。
file-loader: url-loader: 读取文件内容,返回base64编码的字符串,不会转码。
raw-loader: 读取文件内容,返回字符串,不会转码。
source-map-loader: 读取.map文件,返回源码。
VueLoaderPlugin:处理.vue单文件组件
CleanWebpackPlugin:清理构建目录:每次修改了一些配置,重新打包时,帮助我们删除dist文件夹
HtmlWebpackPlugin:对index.html进行打包处理,自动在dist文件夹中,生成了一个index.html的文件
DefinePlugin:定义全局常量,是一个webpack内置的插件(不需要单独安装)
- 比如process.env.NODE_ENV:判断当前环境是开发还是生产
mini-css-extract-plugin: 将CSS提取到单独的文件中。它支持按需加载CSS和源映射
webpack-bundle-size-analyzer: 分析包的大小。
speed-measure-plugin: 测量webpack构建速度。
10.webpack的开发模式和生产模式有什么区别?
- Mode: development 开发模式
- 会将
process.env.NODE_ENV的值设置为development
- 会将
- Mode: production 生产模式
- 会将
process.env.NODE_ENV的值设置为production
- 会将
***11.什么是babel?babel在开发中是什么作用?
- Babel是一个工具链,主要用于旧浏览器或者环境中将ECMAScript 2015+代码转换为向后兼容版本的JavaScript (ES6以上的代码转成ES5代码)
- 作用: 语法转换,源代码转换,箭头函数转换 ,ES6以上的代码转成ES5代码
12.总结整理git常见的命令, 并且说明在什么场景会用到这个命令
git文件大致分为四种状态
- Untracked 未跟踪的文件
- 没有通过git追踪的文件
- 使用git add 使得该文件被追踪
- Unmodified 未修改的
- 已被git记录 但是还没有被修改(比如新创建的文件)
- Modified 已修改的
- 已经进行修改的文件 但是暂时没有进行缓存
- Staged 暂缓区中的文件状态
- 已经提交到git本地缓存中的文件
- 提交缓存之前需要将文件添加到暂存区 git add .
- 之后进行 git commit -m "提交信息"将文件提交到缓存中
- 简写 git commit -a -m ""