Vue3必学的12个JS前置知识,零基础也能懂

🚀 为什么需要学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)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 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引入了letconst来声明变量,替代传统的var,解决了变量提升、块级作用域等问题。

  • let:声明可变的变量,具有块级作用域

  • const:声明常量,声明后不能重新赋值,也具有块级作用域

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 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中的应用

1
2
3
4
5
6
7
8
9
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保证的是变量指向的内存地址不变,而不是值不变。对于引用类型(对象、数组),变量存储的是内存地址(指针),所以可以修改对象内部的属性,但不能让变量指向新的对象。

1
2
3
4
5
const obj = { a: 1 };
// obj存储的是对象的内存地址,比如0x1234

obj.a = 2; // ✅ 修改对象内部属性,内存地址0x1234不变
obj = { a: 2 }; // ❌ 指向新对象,内存地址变了(比如0x5678),违反const约束

⚠️ 注意事项

  • 优先使用const,只有确定变量会改变时才用let

  • 避免使用var(存在变量提升和全局污染问题)

  • const不代表”不可变”,对于引用类型要特别注意


2️⃣ 模板字符串

核心概念

模板字符串使用反引号 `包裹,支持嵌入表达式和多行文本,比传统字符串拼接更简洁易读。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 传统字符串拼接(繁琐)
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中的应用

1
2
3
4
5
6
7
8
9
10
11
12
// 动态绑定class
const isActive = true;
const className = `btn ${isActive ? &#x27;active&#x27; : &#x27;&#x27;}`;

// 模板中的插值
<template>
<div>{{ `用户:${user.name},年龄:${user.age}` }}</div>
</template>

// 动态路由跳转
const userId = 123;
router.push(`/user/${userId}`);

⚠️ 注意事项

  • 模板字符串使用反引号 ,不是单引号‘`

  • 模板字符串会保留空格和换行


核心概念

对象是JavaScript中最重要的数据结构,掌握对象的取值、赋值和简写规则是必备技能。

3.1 点取值 vs 中括号取值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const user = {
name: &#x27;张三&#x27;,
age: 25,
&#x27;home-address&#x27;: &#x27;北京&#x27;
};

// 点取值(常用)
console.log(user.name); // "张三"

// 中括号取值(动态属性名、包含特殊字符时使用)
console.log(user[&#x27;name&#x27;]); // "张三"
console.log(user[&#x27;home-address&#x27;]); // "北京",属性名有特殊字符必须用中括号

// 动态属性名(重要)
const key = &#x27;age&#x27;;
console.log(user[key]); // 25,key是变量

// Vue3中的应用:动态访问对象属性
const formData = { username: &#x27;admin&#x27;, password: &#x27;123456&#x27; };
const fields = [&#x27;username&#x27;, &#x27;password&#x27;];
fields.forEach(field => {
console.log(formData[field]); // 动态访问
});

3.2 属性和方法的简写

4.1 数组解构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 基础用法
const colors = [&#x27;red&#x27;, &#x27;green&#x27;, &#x27;blue&#x27;];
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 对象解构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 基础用法
const user = { name: &#x27;张三&#x27;, age: 25, city: &#x27;北京&#x27; };
const { name, age } = user;
console.log(name, age); // "张三" 25

// 重命名(别名)
const { name: userName, age: userAge } = user;
console.log(userName, userAge); // "张三" 25

// 默认值
const { name, age, gender = &#x27;未知&#x27; } = user;
console.log(gender); // "未知"(user中没有gender属性)

// 剩余运算符
const { name, ...rest } = user;
console.log(rest); // { age: 25, city: &#x27;北京&#x27; }

// 嵌套解构
const student = {
name: &#x27;李四&#x27;,
score: {
math: 90,
english: 85
}
};
const { name, score: { math, english } } = student;
console.log(math, english); // 90 85

4.3 函数参数解构

核心概念

箭头函数是ES6引入的简洁函数写法,在Vue3中大量使用,尤其是在事件处理、计算属性、侦听器中。

语法规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 传统函数
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(&#x27;Hello&#x27;);

// 返回对象需要加括号(重要)
const getUser = () => ({ name: &#x27;张三&#x27;, age: 25 });
// 如果不加括号,{ }会被识别为函数体
const wrong = () => { name: &#x27;张三&#x27; }; // ❌ 返回undefined
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 1. 事件处理
<template>
<button @click="() => count++">点击</button>
<button @click="increment">点击</button>
</template>

<script setup>
import { ref } from &#x27;vue&#x27;;

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(&#x27;组件已挂载&#x27;);
});

⚠️ 注意事项

  • 箭头函数不能作为构造函数使用(不能用new调用)

  • 箭头函数没有arguments对象

  • 返回对象字面量时必须加括号:() => ({ key: value })

  • 在Vue选项式API的methods中不要使用箭头函数


6️⃣ 数组的重要方法

6.1 修改原数组的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
// 语法: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 });
};
1
2
3
4
5
6
// 语法:arr.unshift(元素1, 元素2, ...)
// 返回值:数组新长度

const arr = [1, 2, 3];
arr.unshift(0);
console.log(arr); // [0, 1, 2, 3]
1
2
3
4
5
6
7
// 语法:arr.pop()
// 返回值:被删除的元素

const arr = [1, 2, 3];
const last = arr.pop();
console.log(arr); // [1, 2]
console.log(last); // 3
1
2
3
4
5
6
7
// 语法:arr.shift()
// 返回值:被删除的元素

const arr = [1, 2, 3];
const first = arr.shift();
console.log(arr); // [2, 3]
console.log(first); // 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 语法: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, &#x27;a&#x27;, &#x27;b&#x27;); // 在索引1插入&#x27;a&#x27;和&#x27;b&#x27;
console.log(arr); // [1, &#x27;a&#x27;, &#x27;b&#x27;, 4, 5]

// 替换
arr.splice(1, 2, &#x27;x&#x27;); // 删除索引1开始的2个元素,插入&#x27;x&#x27;
console.log(arr); // [1, &#x27;x&#x27;, 4, 5]

// Vue3应用场景:删除列表项
const deleteItem = (index) => {
list.value.splice(index, 1);
};

6.2 不修改原数组的方法

1
2
3
4
5
6
7
8
9
10
// 语法:arr.includes(元素)
// 返回值:true 或 false

const arr = [1, 2, 3];
console.log(arr.includes(2)); // true
console.log(arr.includes(5)); // false

// Vue3应用场景:判断权限
const permissions = [&#x27;read&#x27;, &#x27;write&#x27;];
const canDelete = permissions.includes(&#x27;delete&#x27;); // false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 语法: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;
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 语法: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: &#x27;张三&#x27; },
{ id: 2, name: &#x27;李四&#x27; }
];
const names = users.map(user => user.name);
console.log(names); // [&#x27;张三&#x27;, &#x27;李四&#x27;]

// Vue3应用场景:数据格式化
const formattedUsers = computed(() => {
return users.value.map(user => ({
...user,
fullName: `${user.firstName} ${user.lastName}`
}));
});
1
2
3
4
5
6
7
8
9
// 语法: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() !== &#x27;&#x27;);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 语法: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 = [&#x27;apple&#x27;, &#x27;banana&#x27;, &#x27;apple&#x27;, &#x27;orange&#x27;, &#x27;banana&#x27;, &#x27;apple&#x27;];
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()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const user = {
name: &#x27;张三&#x27;,
age: 25,
city: &#x27;北京&#x27;
};

// Object.keys() - 获取所有键
const keys = Object.keys(user);
console.log(keys); // [&#x27;name&#x27;, &#x27;age&#x27;, &#x27;city&#x27;]

// Object.values() - 获取所有值
const values = Object.values(user);
console.log(values); // [&#x27;张三&#x27;, 25, &#x27;北京&#x27;]

// Object.entries() - 获取键值对数组
const entries = Object.entries(user);
console.log(entries); // [[&#x27;name&#x27;, &#x27;张三&#x27;], [&#x27;age&#x27;, 25], [&#x27;city&#x27;, &#x27;北京&#x27;]]

结合数组方法遍历对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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); // [&#x27;math&#x27;, &#x27;chinese&#x27;]

Vue3应用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 遍历表单字段验证
const formData = reactive({
username: &#x27;&#x27;,
password: &#x27;&#x27;,
email: &#x27;&#x27;
});

const validateForm = () => {
return Object.keys(formData).every(key => {
return formData[key].trim() !== &#x27;&#x27;;
});
};

// 动态表格列
const columns = {
name: &#x27;姓名&#x27;,
age: &#x27;年龄&#x27;,
city: &#x27;城市&#x27;
};

<template>
<table>
<tr>
<th v-for="(key, value) in columns" :key="key">
{{value}}
</th>
</tr>
</table>
</template>

8️⃣ 扩展运算符(…)

核心概念

扩展运算符(Spread Operator)用三个点...表示,可以展开数组或对象,常用于复制、合并和解决引用类型赋值问题。

8.1 复制数组/对象

1
2
3
4
5
6
7
8
9
10
11
12
// 复制数组(浅拷贝)
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: &#x27;张三&#x27;, age: 25 };
const copiedUser = { ...user };
copiedUser.age = 26;
console.log(user.age); // 25,不受影响

8.2 合并数组/对象

1
2
3
4
5
6
7
8
9
10
11
// 合并数组
const arr1 = [1, 2];
const arr2 = [3, 4];
const merged = [...arr1, ...arr2];
console.log(merged); // [1, 2, 3, 4]

// 合并对象
const defaults = { theme: &#x27;light&#x27;, lang: &#x27;zh&#x27; };
const userSettings = { theme: &#x27;dark&#x27; };
const settings = { ...defaults, ...userSettings };
console.log(settings); // { theme: &#x27;dark&#x27;, lang: &#x27;zh&#x27; }

8.3 同名属性覆盖规则

1
2
3
4
5
6
7
8
9
10
// 后面的属性会覆盖前面的
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: &#x27;张三&#x27;, age: 25 };
const updatedUser = { ...user, age: 26, city: &#x27;北京&#x27; };
console.log(updatedUser); // { name: &#x27;张三&#x27;, age: 26, city: &#x27;北京&#x27; }

8.4 解决引用类型赋值问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// ❌ 错误:直接赋值(引用)
const obj1 = { name: &#x27;张三&#x27; };
const obj2 = obj1; // obj2和obj1指向同一个对象
obj2.name = &#x27;李四&#x27;;
console.log(obj1.name); // "李四",被影响了

// ✅ 正确:使用扩展运算符(复制)
const obj1 = { name: &#x27;张三&#x27; };
const obj2 = { ...obj1 }; // 创建新对象
obj2.name = &#x27;李四&#x27;;
console.log(obj1.name); // "张三",不受影响

// ⚠️ 注意:扩展运算符是浅拷贝
const user = {
name: &#x27;张三&#x27;,
address: { city: &#x27;北京&#x27; }
};
const copiedUser = { ...user };
copiedUser.address.city = &#x27;上海&#x27;;
console.log(user.address.city); // "上海",嵌套对象被影响了
  • 核心逻辑:浅拷贝只复制对象的第一层属性,对于嵌套的对象(比如 address),复制的依然是它的内存引用,而不是嵌套对象本身。

  • 执行结果copiedUser.addressuser.address 指向同一个嵌套对象,修改 copiedUser.address.city 会直接影响 user.address.city,所以输出 “上海”。

  • 如何解决嵌套对象的深拷贝问题呢?这里有两种方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 方法1:JSON 序列化(简单场景,不支持函数、Symbol等)
const deepCopiedUser1 = JSON.parse(JSON.stringify(user));

// 方法2:递归拷贝(通用场景,支持所有类型)
function deepClone(obj) {
if (obj === null || typeof obj !== &#x27;object&#x27;) 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 1. 更新响应式对象
const state = ref({ count: 0, name: &#x27;Vue&#x27; });
state.value = { ...state.value, count: state.value.count + 1 };

// 2. 表单重置
const formData = reactive({ name: &#x27;&#x27;, age: 0 });
const defaultData = { name: &#x27;&#x27;, age: 0 };
const resetForm = () => {
Object.assign(formData, { ...defaultData });
};

// 3. 路由传参
router.push({
name: &#x27;UserDetail&#x27;,
params: { ...user }
});

9️⃣ 序列化和反序列化(JSON)

核心概念

  • 序列化(JSON.stringify):将JavaScript对象转换为JSON字符串

  • 反序列化(JSON.parse):将JSON字符串转换为JavaScript对象

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// JSON.stringify() - 对象转字符串
const user = {
name: &#x27;张三&#x27;,
age: 25,
hobbies: [&#x27;读书&#x27;, &#x27;旅游&#x27;]
};

const jsonStr = JSON.stringify(user);
console.log(jsonStr);
// &#x27;{"name":"张三","age":25,"hobbies":["读书","旅游"]}&#x27;
console.log(typeof jsonStr); // "string"

// JSON.parse() - 字符串转对象
const jsonStr = &#x27;{"name":"张三","age":25}&#x27;;
const obj = JSON.parse(jsonStr);
console.log(obj); // { name: &#x27;张三&#x27;, age: 25 }
console.log(typeof obj); // "object"

// 格式化输出(美化JSON)
const formatted = JSON.stringify(user, null, 2);
console.log(formatted);
/*
{
"name": "张三",
"age": 25,
"hobbies": [
"读书",
"旅游"
]
}
*/

使用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 1. 深拷贝(简单对象)
const obj1 = { name: &#x27;张三&#x27;, age: 25 };
const obj2 = JSON.parse(JSON.stringify(obj1));
obj2.name = &#x27;李四&#x27;;
console.log(obj1.name); // "张三",不受影响

// ⚠️ 注意:JSON方法的局限性
const obj = {
func: () => {}, // 函数会丢失
date: new Date(), // 日期会变成字符串
undef: undefined, // undefined会丢失
sym: Symbol(&#x27;test&#x27;) // Symbol会丢失
};
const copied = JSON.parse(JSON.stringify(obj));
console.log(copied); // { date: "2026-02-09T..." }

// 2. 与Web存储结合使用
localStorage.setItem(&#x27;user&#x27;, JSON.stringify(user)); // 存储
const savedUser = JSON.parse(localStorage.getItem(&#x27;user&#x27;)); // 读取

Vue3应用场景

1
2
3
4
5
6
7
8
9
10
11
12
// API请求
const createUser = async (userData) => {
const response = await fetch(&#x27;/api/users&#x27;, {
method: &#x27;POST&#x27;,
headers: {
&#x27;Content-Type&#x27;: &#x27;application/json&#x27;
},
body: JSON.stringify(userData) // 序列化
});
const result = await response.json(); // 反序列化
return result;
};

🔟 Web存储(localStorage/sessionStorage)

核心概念

浏览器提供了两种Web存储方式:

  • localStorage:永久存储,除非手动清除

  • sessionStorage:会话存储,关闭标签页/浏览器后清除

基本用法

1
2
3
4
5
6
7
8
9
// localStorage - 永久存储
localStorage.setItem(&#x27;username&#x27;, &#x27;张三&#x27;); // 存储
const username = localStorage.getItem(&#x27;username&#x27;); // 获取
localStorage.removeItem(&#x27;username&#x27;); // 删除单个
localStorage.clear(); // 清空所有

// sessionStorage - 会话存储(用法相同)
sessionStorage.setItem(&#x27;token&#x27;, &#x27;abc123&#x27;);
const token = sessionStorage.getItem(&#x27;token&#x27;);

存储引用类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// ⚠️ localStorage只能存储字符串
const user = { name: &#x27;张三&#x27;, age: 25 };

// ❌ 错误:直接存储对象
localStorage.setItem(&#x27;user&#x27;, user); // 会变成"[object Object]"

// ✅ 正确:先序列化,再存储
localStorage.setItem(&#x27;user&#x27;, JSON.stringify(user));

// 读取时需要反序列化
const userStr = localStorage.getItem(&#x27;user&#x27;);
const user = JSON.parse(userStr);
console.log(user); // { name: &#x27;张三&#x27;, 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(&#x27;user&#x27;, { name: &#x27;张三&#x27;, age: 25 });
const user = storage.get(&#x27;user&#x27;);

localStorage vs sessionStorage

特性 localStorage sessionStorage
存储时效 永久存储,除非手动删除 关闭标签页后清除
作用域 同源窗口共享 仅当前标签页
容量限制 约5MB 约5MB
使用场景 用户偏好、登录状态 临时数据、表单草稿

Vue3应用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 1. 持久化用户登录状态
const token = ref(localStorage.getItem(&#x27;token&#x27;) || &#x27;&#x27;);

const login = async (username, password) => {
const res = await api.login(username, password);
token.value = res.token;
localStorage.setItem(&#x27;token&#x27;, res.token); // 持久化
};

const logout = () => {
token.value = &#x27;&#x27;;
localStorage.removeItem(&#x27;token&#x27;);
};

// 2. 记住用户偏好
const theme = ref(localStorage.getItem(&#x27;theme&#x27;) || &#x27;light&#x27;);

watch(theme, (newTheme) => {
localStorage.setItem(&#x27;theme&#x27;, newTheme);
});

// 3. 缓存列表数据
const cacheKey = &#x27;user-list&#x27;;
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 回调地狱问题

1
2
3
4
5
6
7
8
// ❌ 回调地狱:难以维护
getUserInfo(userId, (user) => {
getOrders(user.id, (orders) => {
getOrderDetail(orders[0].id, (detail) => {
console.log(detail);
});
});
});

11.2 Promise基础

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Promise三种状态
// pending(进行中)→ fulfilled(成功)或 rejected(失败)

// 创建Promise
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve(&#x27;成功的数据&#x27;); // 变为fulfilled状态
} else {
reject(&#x27;失败的原因&#x27;); // 变为rejected状态
}
}, 1000);
});

// 使用Promise
promise
.then(data => {
console.log(data); // "成功的数据"
return data + &#x27;1&#x27;; // 可以返回新值
})
.then(data => {
console.log(data); // "成功的数据1"
})
.catch(error => {
console.error(error); // 捕获错误
})
.finally(() => {
console.log(&#x27;无论成功失败都会执行&#x27;);
});

11.3 Promise链式调用消除回调地狱

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 模拟异步函数
function getUserInfo(userId) {
return new Promise((resolve) => {
setTimeout(() => resolve({ id: userId, name: &#x27;张三&#x27; }), 1000);
});
}

function getOrders(userId) {
return new Promise((resolve) => {
setTimeout(() => resolve([{ id: 1, name: &#x27;订单1&#x27; }]), 1000);
});
}

function getOrderDetail(orderId) {
return new Promise((resolve) => {
setTimeout(() => resolve({ id: orderId, price: 100 }), 1000);
});
}

// ✅ Promise链:清晰易读
getUserInfo(123)
.then(user => {
console.log(&#x27;用户信息:&#x27;, user);
return getOrders(user.id);
})
.then(orders => {
console.log(&#x27;订单列表:&#x27;, orders);
return getOrderDetail(orders[0].id);
})
.then(detail => {
console.log(&#x27;订单详情:&#x27;, detail);
})
.catch(error => {
console.error(&#x27;出错了:&#x27;, error);
});

11.4 Async/Await - 异步终极解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// async函数返回Promise
async function fetchUser() {
return { name: &#x27;张三&#x27; }; // 自动包装成Promise
}

fetchUser().then(user => console.log(user));

// await等待Promise完成
async function getUser() {
const user = await getUserInfo(123); // 等待Promise完成
console.log(user); // { id: 123, name: &#x27;张三&#x27; }
}

// ✅ 完整示例:用同步的方式写异步代码
async function loadData() {
try {
const user = await getUserInfo(123);
console.log(&#x27;1. 用户信息:&#x27;, user);

const orders = await getOrders(user.id);
console.log(&#x27;2. 订单列表:&#x27;, orders);

const detail = await getOrderDetail(orders[0].id);
console.log(&#x27;3. 订单详情:&#x27;, detail);

return detail;
} catch (error) {
console.error(&#x27;出错了:&#x27;, error);
} finally {
console.log(&#x27;请求完成&#x27;);
}
}

loadData();

Vue3应用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 1. 组件挂载时请求数据
import { ref, onMounted } from &#x27;vue&#x27;;

const users = ref([]);
const loading = ref(false);
const error = ref(null);

onMounted(async () => {
loading.value = true;
try {
const response = await fetch(&#x27;/api/users&#x27;);
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(&#x27;创建成功&#x27;);
}
};

// 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模块化。

模块化的意义

1
2
3
4
5
6
7
8
9
10
11
12
13
// ❌ 没有模块化:所有代码在一个文件
// 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 &#x27;./utils/math.js&#x27;;

package.json配置

1
2
3
4
5
{
"name": "my-project",
"type": "module",
"version": "1.0.0"
}

⚠️ 注意:添加"type": "module"后,.js文件才能使用ES6模块语法(Node.js环境)。

默认导出/导入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// user.js - 默认导出(每个模块只能有一个)
export default {
name: &#x27;张三&#x27;,
age: 25,
greet() {
console.log(`你好,我是${this.name}`);
}
};

// 或者
const user = { name: &#x27;张三&#x27;, age: 25 };
export default user;

// main.js - 默认导入(名字可以自定义)
import user from &#x27;./user.js&#x27;;
import myUser from &#x27;./user.js&#x27;; // 名字随意
console.log(user.name);

按需导出/导入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 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 &#x27;./utils.js&#x27;;
console.log(PI); // 3.14
console.log(add(1, 2)); // 3

// 导入时重命名
import { add as sum } from &#x27;./utils.js&#x27;;
console.log(sum(1, 2)); // 3

// 导入全部
import * as utils from &#x27;./utils.js&#x27;;
console.log(utils.PI); // 3.14
console.log(utils.add(1, 2)); // 3

混合导出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// user.js - 既有默认导出,又有按需导出
export const VERSION = &#x27;1.0.0&#x27;;

export function formatUser(user) {
return `${user.name} (${user.age}岁)`;
}

export default {
name: &#x27;张三&#x27;,
age: 25
};

// main.js - 同时导入
import user, { VERSION, formatUser } from &#x27;./user.js&#x27;;
console.log(user); // { name: &#x27;张三&#x27;, age: 25 }
console.log(VERSION); // "1.0.0"
console.log(formatUser(user)); // "张三 (25岁)"

Vue3应用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 1. 导入Vue函数
import { ref, reactive, computed, watch, onMounted } from &#x27;vue&#x27;;

// 2. 导入组件
import MyButton from &#x27;./components/MyButton.vue&#x27;;
import MyInput from &#x27;./components/MyInput.vue&#x27;;

// 3. 导入工具函数
import { formatDate, debounce } from &#x27;@/utils/index.js&#x27;;

// 4. 导入API
import * as userApi from &#x27;@/api/user.js&#x27;;

// 5. 组合式函数(Composables)
// composables/useCounter.js
import { ref } from &#x27;vue&#x27;;

export function useCounter(initialValue = 0) {
const count = ref(initialValue);
const increment = () => count.value++;
const decrement = () => count.value--;
return { count, increment, decrement };
}

// 使用
import { useCounter } from &#x27;@/composables/useCounter.js&#x27;;
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高手!💪