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

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)

// 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. 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.addressuser.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

特性localStoragesessionStorage
存储时效永久存储,除非手动删除关闭标签页后清除
作用域同源窗口共享仅当前标签页
容量限制约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高手!💪