现在让我们设好番茄钟放一首好听的音乐开始学习吧 🌈 😋
🚀 为什么需要学Vue3?
Vue3是目前最流行的前端框架之一,学习它有以下几个重要原因:
1. 市场需求旺盛
- 国内大厂(阿里、腾讯、字节跳动等)广泛使用Vue3
- 招聘市场对Vue3开发者需求量大,薪资待遇优厚
- 中小企业也普遍采用Vue技术栈
2. 学习曲线友好
- 中文文档完善,对中国开发者友好
- 渐进式框架设计,可以逐步深入学习
- 社区活跃,学习资源丰富
3. 开发效率高
- 组合式API提高代码复用性
- 响应式系统自动更新UI,无需手动操作DOM
- 丰富的生态系统(Vue Router、Pinia、Element Plus等)
4. 性能优秀
- 虚拟DOM优化,渲染速度快
- 按需编译,打包体积小
- 支持Tree-shaking,减少冗余代码
5. 职业发展
- 掌握Vue3可以开发企业级应用
- 为学习React、Angular等框架打下基础
- 可以转向全栈开发(配合Node.js)
💡 Vue3技术为什么会诞生?
理解Vue3的诞生背景,有助于我们更好地掌握它的设计理念和核心特性。
Vue2遇到的瓶颈
在Vue3诞生之前,Vue2已经非常成熟并被广泛使用。但随着前端应用越来越复杂,Vue2逐渐暴露出一些问题:
1. 大型项目代码组织困难
- Vue2的Options API(选项式API)按照data、methods、computed等选项组织代码
- 同一个功能的逻辑被分散在不同的选项中,维护困难
- 缺乏有效的代码复用机制(Mixins有命名冲突问题)
2. TypeScript支持不够友好
- Vue2使用基于类的组件实现,类型推导困难
this的类型推导存在局限- 大型团队协作时类型安全得不到保障
3. 性能优化空间有限
- 响应式系统基于Object.defineProperty,存在性能瓶颈
- 无法监听数组索引和对象属性的新增/删除
- 虚拟DOM的diff算法还有优化空间
- 打包体积较大,不支持Tree-shaking
4. 移动端和跨平台支持受限
- 对移动端性能优化不够
- 难以与原生应用深度集成
Vue3的技术革新
为了解决这些问题,尤雨溪和Vue核心团队从2018年开始重写Vue,经过2年多的开发,于2020年9月发布了Vue3。
核心改进:
1. 组合式API(Composition API)
// Vue2 Options API - 逻辑分散
export default {
data() {
return { count: 0, user: {} }
},
methods: {
increment() { this.count++ },
fetchUser() { /* ... */ }
},
computed: {
doubleCount() { return this.count * 2 }
}
}
// Vue3 Composition API - 逻辑聚合
import { ref, computed } from 'vue'
export default {
setup() {
// 计数器功能
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
const increment = () => count.value++
// 用户功能
const user = ref({})
const fetchUser = () => { /* ... */ }
return { count, doubleCount, increment, user, fetchUser }
}
}
2. 更好的TypeScript支持
- 完全用TypeScript重写
- 类型推导更准确
- 开发体验大幅提升
3. 性能提升
- 使用Proxy重写响应式系统,性能提升约1.2-2倍
- 虚拟DOM重构,更新性能提升约1.3-2倍
- 编译时优化(静态提升、预字符串化等)
- 打包体积减少约41%(13.5kb → 10kb)
- 支持Tree-shaking,按需引入
4. 新的核心特性
- Teleport(传送门)组件
- Fragments(多根节点)
- Suspense(异步组件处理)
- 更好的自定义渲染器API
5. 生态系统升级
- Vue Router 4:更好的TypeScript支持
- Pinia:替代Vuex的新一代状态管理
- Vite:极速的开发构建工具
- Vitest:快速的单元测试框架
Vue3的技术目标
Vue3的设计遵循以下原则:
✅ 向下兼容 – 保持Vue的核心理念,降低迁移成本
✅ 更快更小 – 性能优化和打包体积优化
✅ 更好的开发体验 – TypeScript支持、更好的调试工具
✅ 面向未来 – 为未来的Web标准和需求做准备
📖 引言
如果你准备学习Vue3,那么扎实的JavaScript基础是必不可少的。Vue3的组合式API(Composition API)、响应式系统、组件通信等核心特性,都建立在现代JavaScript(ES6+)的基础之上。
本文将系统梳理Vue3开发中高频使用的12个JavaScript核心知识点,每个知识点都配有完整的代码示例、详细解析和Vue3应用场景说明。无论你是前端新手还是想快速入门Vue3,这篇文章都能帮你打下坚实的JS基础。 🤗
1️⃣ 变量和常量(let/const)
核心概念
ES6引入了let和const来声明变量,替代传统的var,解决了变量提升、块级作用域等问题。
- let:声明可变的变量,具有块级作用域
- const:声明常量,声明后不能重新赋值,也具有块级作用域
代码示例
// 1. let声明的变量可以修改
let count = 0;
count = 1; // ✅ 可以修改
// 2. const声明的常量不能重新赋值
const MAX_COUNT = 100;
MAX_COUNT = 200; // ❌ 报错:Assignment to constant variable
// 3. 块级作用域
if (true) {
let blockVar = 'block';
const BLOCK_CONST = 'const';
}
console.log(blockVar); // ❌ 报错:blockVar未定义
// 4. const修饰引用类型的特性(重点)
const user = { name: '张三', age: 25 };
user.age = 26; // ✅ 可以修改对象的属性
user = {}; // ❌ 报错:不能重新赋值
const arr = [1, 2, 3];
arr.push(4); // ✅ 可以修改数组内容
arr = []; // ❌ 报错:不能重新赋值
Vue3中的应用
import { ref, reactive } from 'vue';
// Vue3组合式API中大量使用const
const count = ref(0); // 响应式引用
const state = reactive({ name: 'Vue3' }); // 响应式对象
const increment = () => {
count.value++; // 可以修改.value属性
};
🤔 思考问题
Q:为什么const声明的对象可以修改属性,但不能重新赋值?
A:const保证的是变量指向的内存地址不变,而不是值不变。对于引用类型(对象、数组),变量存储的是内存地址(指针),所以可以修改对象内部的属性,但不能让变量指向新的对象。
const obj = { a: 1 };
// obj存储的是对象的内存地址,比如0x1234
obj.a = 2; // ✅ 修改对象内部属性,内存地址0x1234不变
obj = { a: 2 }; // ❌ 指向新对象,内存地址变了(比如0x5678),违反const约束
⚠️ 注意事项
- 优先使用
const,只有确定变量会改变时才用let - 避免使用
var(存在变量提升和全局污染问题) const不代表"不可变",对于引用类型要特别注意
2️⃣ 模板字符串
核心概念
模板字符串使用反引号 `包裹,支持嵌入表达式和多行文本,比传统字符串拼接更简洁易读。
代码示例
// 传统字符串拼接(繁琐)
const name = 'Vue3';
const version = 3.4;
const message1 = '欢迎学习 ' + name + ' 版本 ' + version;
// 模板字符串(推荐)
const message2 = `欢迎学习 ${name} 版本 ${version}`;
// 多行文本
const html = `
<div class="container">
<h1>${name}</h1>
<p>版本:${version}</p>
</div>
`;
// 嵌入表达式
const price = 100;
const discount = 0.8;
const finalPrice = `最终价格:${price * discount}元`; // "最终价格:80元"
// 调用函数
const greeting = `你好,${name.toUpperCase()}!`; // "你好,VUE3!"
与普通字符串的区别
| 特性 | 普通字符串 | 模板字符串 |
|---|---|---|
| 包裹符号 | ' 或 " | ` |
| 多行文本 | 需要用n或字符串拼接 | 直接换行 |
| 嵌入变量 | 需要用+拼接 | ${变量} |
| 嵌入表达式 | 不支持 | ${表达式} |
Vue3中的应用
// 动态绑定class
const isActive = true;
const className = `btn ${isActive ? 'active' : ''}`;
// 模板中的插值
<template>
<div>{{ `用户:${user.name},年龄:${user.age}` }}</div>
</template>
// 动态路由跳转
const userId = 123;
router.push(`/user/${userId}`);
⚠️ 注意事项
- 模板字符串使用反引号
,不是单引号'` - 模板字符串会保留空格和换行
核心概念
对象是JavaScript中最重要的数据结构,掌握对象的取值、赋值和简写规则是必备技能。
3.1 点取值 vs 中括号取值
const user = {
name: '张三',
age: 25,
'home-address': '北京'
};
// 点取值(常用)
console.log(user.name); // "张三"
// 中括号取值(动态属性名、包含特殊字符时使用)
console.log(user['name']); // "张三"
console.log(user['home-address']); // "北京",属性名有特殊字符必须用中括号
// 动态属性名(重要)
const key = 'age';
console.log(user[key]); // 25,key是变量
// Vue3中的应用:动态访问对象属性
const formData = { username: 'admin', password: '123456' };
const fields = ['username', 'password'];
fields.forEach(field => {
console.log(formData[field]); // 动态访问
});
3.2 属性和方法的简写
4.1 数组解构
// 基础用法
const colors = ['red', 'green', 'blue'];
const [first, second, third] = colors;
console.log(first); // "red"
console.log(second); // "green"
// 跳过某些元素
const [r, , b] = colors;
console.log(r, b); // "red" "blue"
// 剩余运算符(...rest)
const numbers = [1, 2, 3, 4, 5];
const [one, two, ...rest] = numbers;
console.log(one, two); // 1 2
console.log(rest); // [3, 4, 5]
// 默认值
const [x = 10, y = 20] = [1];
console.log(x, y); // 1 20(y使用默认值)
4.2 对象解构
// 基础用法
const user = { name: '张三', age: 25, city: '北京' };
const { name, age } = user;
console.log(name, age); // "张三" 25
// 重命名(别名)
const { name: userName, age: userAge } = user;
console.log(userName, userAge); // "张三" 25
// 默认值
const { name, age, gender = '未知' } = user;
console.log(gender); // "未知"(user中没有gender属性)
// 剩余运算符
const { name, ...rest } = user;
console.log(rest); // { age: 25, city: '北京' }
// 嵌套解构
const student = {
name: '李四',
score: {
math: 90,
english: 85
}
};
const { name, score: { math, english } } = student;
console.log(math, english); // 90 85
4.3 函数参数解构
核心概念
箭头函数是ES6引入的简洁函数写法,在Vue3中大量使用,尤其是在事件处理、计算属性、侦听器中。
语法规则
// 传统函数
function add(a, b) {
return a + b;
}
// 箭头函数基础语法
const add = (a, b) => {
return a + b;
};
// 单个参数可省略括号
const double = x => x * 2;
// 单行return可省略return和大括号
const add = (a, b) => a + b;
// 无参数
const greet = () => console.log('Hello');
// 返回对象需要加括号(重要)
const getUser = () => ({ name: '张三', age: 25 });
// 如果不加括号,{ }会被识别为函数体
const wrong = () => { name: '张三' }; // ❌ 返回undefined
// 1. 事件处理
<template>
<button @click="() => count++">点击</button>
<button @click="increment">点击</button>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
const increment = () => {
count.value++;
};
</script>
// 2. 计算属性
const doubleCount = computed(() => count.value * 2);
// 3. 侦听器
watch(count, (newVal, oldVal) => {
console.log(`从${oldVal}变为${newVal}`);
});
// 4. 生命周期钩子
onMounted(() => {
console.log('组件已挂载');
});
⚠️ 注意事项
- 箭头函数不能作为构造函数使用(不能用
new调用) - 箭头函数没有
arguments对象 - 返回对象字面量时必须加括号:
() => ({ key: value }) - 在Vue选项式API的
methods中不要使用箭头函数
6️⃣ 数组的重要方法
6.1 修改原数组的方法
// 语法:arr.push(元素1, 元素2, ...)
// 返回值:数组新长度
const arr = [1, 2, 3];
const newLength = arr.push(4, 5);
console.log(arr); // [1, 2, 3, 4, 5]
console.log(newLength); // 5
// Vue3应用场景:添加列表项
const todos = ref([]);
const addTodo = (text) => {
todos.value.push({ id: Date.now(), text, done: false });
};
// 语法:arr.unshift(元素1, 元素2, ...)
// 返回值:数组新长度
const arr = [1, 2, 3];
arr.unshift(0);
console.log(arr); // [0, 1, 2, 3]
// 语法:arr.pop()
// 返回值:被删除的元素
const arr = [1, 2, 3];
const last = arr.pop();
console.log(arr); // [1, 2]
console.log(last); // 3
// 语法:arr.shift()
// 返回值:被删除的元素
const arr = [1, 2, 3];
const first = arr.shift();
console.log(arr); // [2, 3]
console.log(first); // 1
// 语法:arr.splice(起始索引, 删除个数, 插入元素...)
// 返回值:被删除元素组成的数组
const arr = [1, 2, 3, 4, 5];
// 删除
arr.splice(1, 2); // 从索引1开始删除2个元素
console.log(arr); // [1, 4, 5]
// 插入
arr.splice(1, 0, 'a', 'b'); // 在索引1插入'a'和'b'
console.log(arr); // [1, 'a', 'b', 4, 5]
// 替换
arr.splice(1, 2, 'x'); // 删除索引1开始的2个元素,插入'x'
console.log(arr); // [1, 'x', 4, 5]
// Vue3应用场景:删除列表项
const deleteItem = (index) => {
list.value.splice(index, 1);
};
6.2 不修改原数组的方法
// 语法:arr.includes(元素)
// 返回值:true 或 false
const arr = [1, 2, 3];
console.log(arr.includes(2)); // true
console.log(arr.includes(5)); // false
// Vue3应用场景:判断权限
const permissions = ['read', 'write'];
const canDelete = permissions.includes('delete'); // false
// 语法:arr.forEach((item, index, array) => {})
// 返回值:undefined
const arr = [1, 2, 3];
arr.forEach((item, index) => {
console.log(`索引${index}:${item}`);
});
// 输出:
// 索引0:1
// 索引1:2
// 索引2:3
// ⚠️ 注意:forEach没有返回值,不能用break中断
// Vue3应用场景:批量处理
users.value.forEach(user => {
user.isSelected = false;
});
// 语法:arr.map((item, index, array) => 新值)
// 返回值:转换后的新数组
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);
console.log(doubled); // [2, 4, 6]
// 提取对象属性
const users = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' }
];
const names = users.map(user => user.name);
console.log(names); // ['张三', '李四']
// Vue3应用场景:数据格式化
const formattedUsers = computed(() => {
return users.value.map(user => ({
...user,
fullName: `${user.firstName} ${user.lastName}`
}));
});
// 语法:arr.every((item, index, array) => 条件)
// 返回值:true(全部满足)或 false
const numbers = [2, 4, 6, 8];
const allEven = numbers.every(n => n % 2 === 0);
console.log(allEven); // true
// Vue3应用场景:表单验证
const allValid = formFields.every(field => field.value.trim() !== '');
// 语法:arr.reduce((累加器, 当前值, 索引, 数组) => 返回值, 初始值)
// 返回值:最终累加结果
// 求和
const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((acc, cur) => acc + cur, 0);
console.log(sum); // 10
// 求最大值
const max = numbers.reduce((acc, cur) => Math.max(acc, cur));
console.log(max); // 4
// 统计出现次数
const fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'];
const count = fruits.reduce((acc, fruit) => {
acc[fruit] = (acc[fruit] || 0) + 1;
return acc;
}, {});
console.log(count); // { apple: 3, banana: 2, orange: 1 }
// Vue3应用场景:计算购物车总价
const totalPrice = computed(() => {
return cart.value.reduce((total, item) => {
return total + item.price * item.quantity;
}, 0);
});
6.3 对象的重要方法
Object.keys() / values() / entries()
const user = {
name: '张三',
age: 25,
city: '北京'
};
// Object.keys() - 获取所有键
const keys = Object.keys(user);
console.log(keys); // ['name', 'age', 'city']
// Object.values() - 获取所有值
const values = Object.values(user);
console.log(values); // ['张三', 25, '北京']
// Object.entries() - 获取键值对数组
const entries = Object.entries(user);
console.log(entries); // [['name', '张三'], ['age', 25], ['city', '北京']]
结合数组方法遍历对象
const scores = {
math: 90,
english: 85,
chinese: 88
};
// 遍历输出
Object.keys(scores).forEach(subject => {
console.log(`${subject}: ${scores[subject]}分`);
});
// 计算总分
const total = Object.values(scores).reduce((sum, score) => sum + score, 0);
console.log(total); // 263
// 过滤高分科目
const highScores = Object.entries(scores)
.filter(([subject, score]) => score >= 88)
.map(([subject, score]) => subject);
console.log(highScores); // ['math', 'chinese']
Vue3应用场景
// 遍历表单字段验证
const formData = reactive({
username: '',
password: '',
email: ''
});
const validateForm = () => {
return Object.keys(formData).every(key => {
return formData[key].trim() !== '';
});
};
// 动态表格列
const columns = {
name: '姓名',
age: '年龄',
city: '城市'
};
<template>
<table>
<tr>
<th v-for="(key, value) in columns" :key="key">
{{value}}
</th>
</tr>
</table>
</template>
8️⃣ 扩展运算符(…)
核心概念
扩展运算符(Spread Operator)用三个点...表示,可以展开数组或对象,常用于复制、合并和解决引用类型赋值问题。
8.1 复制数组/对象
// 复制数组(浅拷贝)
const arr1 = [1, 2, 3];
const arr2 = [...arr1];
arr2.push(4);
console.log(arr1); // [1, 2, 3],不受影响
console.log(arr2); // [1, 2, 3, 4]
// 复制对象(浅拷贝)
const user = { name: '张三', age: 25 };
const copiedUser = { ...user };
copiedUser.age = 26;
console.log(user.age); // 25,不受影响
8.2 合并数组/对象
// 合并数组
const arr1 = [1, 2];
const arr2 = [3, 4];
const merged = [...arr1, ...arr2];
console.log(merged); // [1, 2, 3, 4]
// 合并对象
const defaults = { theme: 'light', lang: 'zh' };
const userSettings = { theme: 'dark' };
const settings = { ...defaults, ...userSettings };
console.log(settings); // { theme: 'dark', lang: 'zh' }
8.3 同名属性覆盖规则
// 后面的属性会覆盖前面的
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const merged = { ...obj1, ...obj2 };
console.log(merged); // { a: 1, b: 3, c: 4 }
// 添加/修改属性
const user = { name: '张三', age: 25 };
const updatedUser = { ...user, age: 26, city: '北京' };
console.log(updatedUser); // { name: '张三', age: 26, city: '北京' }
8.4 解决引用类型赋值问题
// ❌ 错误:直接赋值(引用)
const obj1 = { name: '张三' };
const obj2 = obj1; // obj2和obj1指向同一个对象
obj2.name = '李四';
console.log(obj1.name); // "李四",被影响了
// ✅ 正确:使用扩展运算符(复制)
const obj1 = { name: '张三' };
const obj2 = { ...obj1 }; // 创建新对象
obj2.name = '李四';
console.log(obj1.name); // "张三",不受影响
// ⚠️ 注意:扩展运算符是浅拷贝
const user = {
name: '张三',
address: { city: '北京' }
};
const copiedUser = { ...user };
copiedUser.address.city = '上海';
console.log(user.address.city); // "上海",嵌套对象被影响了
- 核心逻辑:浅拷贝只复制对象的第一层属性,对于嵌套的对象(比如
address),复制的依然是它的内存引用,而不是嵌套对象本身。 - 执行结果:
copiedUser.address和user.address指向同一个嵌套对象,修改copiedUser.address.city会直接影响user.address.city,所以输出 "上海"。 - 如何解决嵌套对象的深拷贝问题呢?这里有两种方法:
// 方法1:JSON 序列化(简单场景,不支持函数、Symbol等)
const deepCopiedUser1 = JSON.parse(JSON.stringify(user));
// 方法2:递归拷贝(通用场景,支持所有类型)
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
if (obj instanceof Array) return obj.map(item => deepClone(item));
if (obj instanceof Object) {
const newObj = {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = deepClone(obj[key]);
}
}
return newObj;
}
}
const deepCopiedUser2 = deepClone(user);
Vue3应用场景
// 1. 更新响应式对象
const state = ref({ count: 0, name: 'Vue' });
state.value = { ...state.value, count: state.value.count + 1 };
// 2. 表单重置
const formData = reactive({ name: '', age: 0 });
const defaultData = { name: '', age: 0 };
const resetForm = () => {
Object.assign(formData, { ...defaultData });
};
// 3. 路由传参
router.push({
name: 'UserDetail',
params: { ...user }
});
9️⃣ 序列化和反序列化(JSON)
核心概念
- 序列化(JSON.stringify):将JavaScript对象转换为JSON字符串
- 反序列化(JSON.parse):将JSON字符串转换为JavaScript对象
代码示例
// JSON.stringify() - 对象转字符串
const user = {
name: '张三',
age: 25,
hobbies: ['读书', '旅游']
};
const jsonStr = JSON.stringify(user);
console.log(jsonStr);
// '{"name":"张三","age":25,"hobbies":["读书","旅游"]}'
console.log(typeof jsonStr); // "string"
// JSON.parse() - 字符串转对象
const jsonStr = '{"name":"张三","age":25}';
const obj = JSON.parse(jsonStr);
console.log(obj); // { name: '张三', age: 25 }
console.log(typeof obj); // "object"
// 格式化输出(美化JSON)
const formatted = JSON.stringify(user, null, 2);
console.log(formatted);
/*
{
"name": "张三",
"age": 25,
"hobbies": [
"读书",
"旅游"
]
}
*/
使用场景
// 1. 深拷贝(简单对象)
const obj1 = { name: '张三', age: 25 };
const obj2 = JSON.parse(JSON.stringify(obj1));
obj2.name = '李四';
console.log(obj1.name); // "张三",不受影响
// ⚠️ 注意:JSON方法的局限性
const obj = {
func: () => {}, // 函数会丢失
date: new Date(), // 日期会变成字符串
undef: undefined, // undefined会丢失
sym: Symbol('test') // Symbol会丢失
};
const copied = JSON.parse(JSON.stringify(obj));
console.log(copied); // { date: "2026-02-09T..." }
// 2. 与Web存储结合使用
localStorage.setItem('user', JSON.stringify(user)); // 存储
const savedUser = JSON.parse(localStorage.getItem('user')); // 读取
Vue3应用场景
// API请求
const createUser = async (userData) => {
const response = await fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(userData) // 序列化
});
const result = await response.json(); // 反序列化
return result;
};
🔟 Web存储(localStorage/sessionStorage)
核心概念
浏览器提供了两种Web存储方式:
- localStorage:永久存储,除非手动清除
- sessionStorage:会话存储,关闭标签页/浏览器后清除
基本用法
// localStorage - 永久存储
localStorage.setItem('username', '张三'); // 存储
const username = localStorage.getItem('username'); // 获取
localStorage.removeItem('username'); // 删除单个
localStorage.clear(); // 清空所有
// sessionStorage - 会话存储(用法相同)
sessionStorage.setItem('token', 'abc123');
const token = sessionStorage.getItem('token');
存储引用类型
// ⚠️ localStorage只能存储字符串
const user = { name: '张三', age: 25 };
// ❌ 错误:直接存储对象
localStorage.setItem('user', user); // 会变成"[object Object]"
// ✅ 正确:先序列化,再存储
localStorage.setItem('user', JSON.stringify(user));
// 读取时需要反序列化
const userStr = localStorage.getItem('user');
const user = JSON.parse(userStr);
console.log(user); // { name: '张三', age: 25 }
// 完整示例:封装存储工具
const storage = {
set(key, value) {
localStorage.setItem(key, JSON.stringify(value));
},
get(key) {
const value = localStorage.getItem(key);
return value ? JSON.parse(value) : null;
},
remove(key) {
localStorage.removeItem(key);
},
clear() {
localStorage.clear();
}
};
// 使用
storage.set('user', { name: '张三', age: 25 });
const user = storage.get('user');
localStorage vs sessionStorage
| 特性 | localStorage | sessionStorage |
|---|---|---|
| 存储时效 | 永久存储,除非手动删除 | 关闭标签页后清除 |
| 作用域 | 同源窗口共享 | 仅当前标签页 |
| 容量限制 | 约5MB | 约5MB |
| 使用场景 | 用户偏好、登录状态 | 临时数据、表单草稿 |
Vue3应用场景
// 1. 持久化用户登录状态
const token = ref(localStorage.getItem('token') || '');
const login = async (username, password) => {
const res = await api.login(username, password);
token.value = res.token;
localStorage.setItem('token', res.token); // 持久化
};
const logout = () => {
token.value = '';
localStorage.removeItem('token');
};
// 2. 记住用户偏好
const theme = ref(localStorage.getItem('theme') || 'light');
watch(theme, (newTheme) => {
localStorage.setItem('theme', newTheme);
});
// 3. 缓存列表数据
const cacheKey = 'user-list';
const users = ref([]);
onMounted(() => {
const cached = localStorage.getItem(cacheKey);
if (cached) {
users.value = JSON.parse(cached);
} else {
fetchUsers();
}
});
const fetchUsers = async () => {
users.value = await api.getUsers();
localStorage.setItem(cacheKey, JSON.stringify(users.value));
};
⚠️ 注意事项
- 存储容量限制:约5MB(不同浏览器略有差异)
- 只能存储字符串,对象需要序列化
- 同步操作,大量数据可能阻塞主线程
- 敏感信息(密码、身份证)不要存储在localStorage
1️⃣1️⃣ Promise 与 Async/Await
核心概念
异步编程是JavaScript的重点难点,Vue3中的数据请求、延时操作都基于Promise和Async/Await。
11.1 回调地狱问题
// ❌ 回调地狱:难以维护
getUserInfo(userId, (user) => {
getOrders(user.id, (orders) => {
getOrderDetail(orders[0].id, (detail) => {
console.log(detail);
});
});
});
11.2 Promise基础
// Promise三种状态
// pending(进行中)→ fulfilled(成功)或 rejected(失败)
// 创建Promise
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve('成功的数据'); // 变为fulfilled状态
} else {
reject('失败的原因'); // 变为rejected状态
}
}, 1000);
});
// 使用Promise
promise
.then(data => {
console.log(data); // "成功的数据"
return data + '1'; // 可以返回新值
})
.then(data => {
console.log(data); // "成功的数据1"
})
.catch(error => {
console.error(error); // 捕获错误
})
.finally(() => {
console.log('无论成功失败都会执行');
});
11.3 Promise链式调用消除回调地狱
// 模拟异步函数
function getUserInfo(userId) {
return new Promise((resolve) => {
setTimeout(() => resolve({ id: userId, name: '张三' }), 1000);
});
}
function getOrders(userId) {
return new Promise((resolve) => {
setTimeout(() => resolve([{ id: 1, name: '订单1' }]), 1000);
});
}
function getOrderDetail(orderId) {
return new Promise((resolve) => {
setTimeout(() => resolve({ id: orderId, price: 100 }), 1000);
});
}
// ✅ Promise链:清晰易读
getUserInfo(123)
.then(user => {
console.log('用户信息:', user);
return getOrders(user.id);
})
.then(orders => {
console.log('订单列表:', orders);
return getOrderDetail(orders[0].id);
})
.then(detail => {
console.log('订单详情:', detail);
})
.catch(error => {
console.error('出错了:', error);
});
11.4 Async/Await – 异步终极解决方案
// async函数返回Promise
async function fetchUser() {
return { name: '张三' }; // 自动包装成Promise
}
fetchUser().then(user => console.log(user));
// await等待Promise完成
async function getUser() {
const user = await getUserInfo(123); // 等待Promise完成
console.log(user); // { id: 123, name: '张三' }
}
// ✅ 完整示例:用同步的方式写异步代码
async function loadData() {
try {
const user = await getUserInfo(123);
console.log('1. 用户信息:', user);
const orders = await getOrders(user.id);
console.log('2. 订单列表:', orders);
const detail = await getOrderDetail(orders[0].id);
console.log('3. 订单详情:', detail);
return detail;
} catch (error) {
console.error('出错了:', error);
} finally {
console.log('请求完成');
}
}
loadData();
Vue3应用场景
// 1. 组件挂载时请求数据
import { ref, onMounted } from 'vue';
const users = ref([]);
const loading = ref(false);
const error = ref(null);
onMounted(async () => {
loading.value = true;
try {
const response = await fetch('/api/users');
users.value = await response.json();
} catch (err) {
error.value = err.message;
} finally {
loading.value = false;
}
});
// 2. 提交表单
const submitForm = async () => {
const valid = await validateForm();
if (!valid) return;
const result = await api.createUser(formData);
if (result.success) {
ElMessage.success('创建成功');
}
};
// 3. 并行请求
const loadPageData = async () => {
const [users, posts, comments] = await Promise.all([
api.getUsers(),
api.getPosts(),
api.getComments()
]);
// 三个请求同时发起,全部完成后继续
};
⚠️ 注意事项
await只能在async函数内使用async函数总是返回Promise- 使用
try/catch捕获异步错误 - 多个无依赖的异步操作用
Promise.all并行执行
1️⃣2️⃣ ES6模块化
核心概念
模块化可以将代码拆分成多个文件,提高可维护性和复用性。Vue3项目全部采用ES6模块化。
模块化的意义
// ❌ 没有模块化:所有代码在一个文件
// main.js (5000行代码...)
function add() {}
function subtract() {}
// 难以维护、代码冗长
// ✅ 使用模块化:拆分成多个文件
// utils/math.js
export function add(a, b) { return a + b; }
export function subtract(a, b) { return a - b; }
// main.js
import { add } from './utils/math.js';
package.json配置
{
"name": "my-project",
"type": "module",
"version": "1.0.0"
}
⚠️ 注意:添加"type": "module"后,.js文件才能使用ES6模块语法(Node.js环境)。
默认导出/导入
// user.js - 默认导出(每个模块只能有一个)
export default {
name: '张三',
age: 25,
greet() {
console.log(`你好,我是${this.name}`);
}
};
// 或者
const user = { name: '张三', age: 25 };
export default user;
// main.js - 默认导入(名字可以自定义)
import user from './user.js';
import myUser from './user.js'; // 名字随意
console.log(user.name);
按需导出/导入
// utils.js - 按需导出(可以多个)
export const PI = 3.14;
export function add(a, b) {
return a + b;
}
export function multiply(a, b) {
return a * b;
}
// 也可以统一导出
const PI = 3.14;
function add(a, b) { return a + b; }
function multiply(a, b) { return a * b; }
export { PI, add, multiply };
// main.js - 按需导入(名字必须一致)
import { PI, add } from './utils.js';
console.log(PI); // 3.14
console.log(add(1, 2)); // 3
// 导入时重命名
import { add as sum } from './utils.js';
console.log(sum(1, 2)); // 3
// 导入全部
import * as utils from './utils.js';
console.log(utils.PI); // 3.14
console.log(utils.add(1, 2)); // 3
混合导出
// user.js - 既有默认导出,又有按需导出
export const VERSION = '1.0.0';
export function formatUser(user) {
return `${user.name} (${user.age}岁)`;
}
export default {
name: '张三',
age: 25
};
// main.js - 同时导入
import user, { VERSION, formatUser } from './user.js';
console.log(user); // { name: '张三', age: 25 }
console.log(VERSION); // "1.0.0"
console.log(formatUser(user)); // "张三 (25岁)"
Vue3应用场景
// 1. 导入Vue函数
import { ref, reactive, computed, watch, onMounted } from 'vue';
// 2. 导入组件
import MyButton from './components/MyButton.vue';
import MyInput from './components/MyInput.vue';
// 3. 导入工具函数
import { formatDate, debounce } from '@/utils/index.js';
// 4. 导入API
import * as userApi from '@/api/user.js';
// 5. 组合式函数(Composables)
// composables/useCounter.js
import { ref } from 'vue';
export function useCounter(initialValue = 0) {
const count = ref(initialValue);
const increment = () => count.value++;
const decrement = () => count.value--;
return { count, increment, decrement };
}
// 使用
import { useCounter } from '@/composables/useCounter.js';
const { count, increment } = useCounter(10);
🎯 知识点总结
恭喜你完成了Vue3前置JavaScript知识的学习!让我们回顾一下12个核心知识点:
| 知识点 | 核心要点 | Vue3应用频率 |
|---|---|---|
| 1. let/const | 块级作用域、const修饰引用类型 | ⭐⭐⭐⭐⭐ |
| 2. 模板字符串 | 包裹、${}`嵌入表达式 | ⭐⭐⭐⭐ |
| 3. 对象操作 | 点取值/中括号取值、属性方法简写 | ⭐⭐⭐⭐⭐ |
| 4. 解构赋值 | 数组/对象解构、剩余运算符 | ⭐⭐⭐⭐⭐ |
| 5. 箭头函数 | 简洁语法、this继承 | ⭐⭐⭐⭐⭐ |
| 6. 数组方法 | map/filter/reduce/forEach等 | ⭐⭐⭐⭐⭐ |
| 7. Object方法 | keys/values/entries | ⭐⭐⭐⭐ |
| 8. 扩展运算符 | ...复制/合并 | ⭐⭐⭐⭐⭐ |
| 9. JSON序列化 | stringify/parse | ⭐⭐⭐ |
| 10. Web存储 | localStorage/sessionStorage | ⭐⭐⭐⭐ |
| 11. Promise/Await | 异步编程 | ⭐⭐⭐⭐⭐ |
| 12. ES6模块化 | 导出/导入 | ⭐⭐⭐⭐⭐ |
📚 学习建议
如何实操练习
1. 搭建练习环境
- 方式1:浏览器Console(F12)
- 方式2:在线工具(CodePen、JSFiddle)
- 方式3:Node.js环境(推荐)
2. 每日一练(2周计划)
- 第1-3天:let/const、模板字符串、对象操作
- 第4-6天:解构赋值、箭头函数
- 第7-9天:数组方法(重点练习map/filter/reduce)
- 第10-11天:扩展运算符、JSON、Web存储
- 第12-14天:Promise/Async/Await、ES6模块化
3. 实战项目练习
- 任务清单(TodoList):练习数组方法、localStorage
- 用户管理系统:练习对象操作、Promise、模块化
- 商品筛选器:练习filter、computed
重点掌握内容(Vue3高频)
必须熟练掌握(⭐⭐⭐⭐⭐):
- const/let的使用
- 对象解构赋值
- 箭头函数
- 数组方法:map、filter、forEach
- 扩展运算符
- Async/Await
- ES6模块化
需要理解(⭐⭐⭐⭐):
- 模板字符串
- 对象方法(Object.keys等)
- Promise链式调用
- localStorage存储
下一步:开始学Vue3
完成这些前置知识后,你已经具备了学习Vue3的基础。建议按以下顺序学习:
1. Vue3基础
- 组合式API(setup、ref、reactive)
- 模板语法(插值、指令)
- 计算属性和侦听器
2. Vue3组件
- 组件注册和使用
- Props和Emits
- 插槽(Slots)
3. Vue3进阶
- 组合式函数(Composables)
- 生命周期钩子
- 路由(Vue Router)
- 状态管理(Pinia)
💡 推荐资源:
🚀 结语
JavaScript是前端开发的基石,而这12个知识点是Vue3开发的"高频词汇"。不要追求一次性全部掌握,而是要在实践中反复练习,遇到不懂的就回来复习。
记住:看懂代码 ≠ 会写代码。动手练习才是王道!
祝你学习顺利,早日成为Vue3高手!💪

