Vue 3 之 语法糖,箭头函数、函数声明

文章目录

  • [1. 箭头函数](#1. 箭头函数)
  • [2. 函数声明](#2. 函数声明)
  • [3. 语法糖](#3. 语法糖)
  • [4. 箭头函数 VS 函数声明](#4. 箭头函数 VS 函数声明)
    • [1. `this` 绑定](#1. this 绑定)
    • [2. 函数提升](#2. 函数提升)
    • [3. 用作构造函数](#3. 用作构造函数)

1. 箭头函数

在 Vue 3 中,箭头函数被广泛支持,尤其是在组合式 API 的上下文中。箭头函数提供了一个更简洁的函数书写方式,并且不绑定自己的 this 上下文,这在某些情况下非常有用。但是,需要注意的是,在 Vue 的选项式 API 中,特别是在 methods 和生命周期钩子中,通常不推荐使用箭头函数,因为这些地方的 this 上下文指向组件实例,使用箭头函数会导致 this 丢失。

javascript 复制代码
// 选项式 API 中不推荐
export default {
  methods: {
    handleClick: () => {
      console.log(this.someData); // this 不会指向组件实例,可能导致错误
    }
  }
}

// 组合式 API 中推荐
import { ref } from 'vue';
export default {
  setup() {
    const count = ref(0);
    const increment = () => {
      count.value++;
    };
    return { count, increment };
  }
}

2. 函数声明

函数声明(或称为命名函数)在 Vue 3 中同样适用,尤其是在定义组件方法或者处理器时。相较于箭头函数,命名函数有明确的名称,更利于调试和递归调用,并且自然绑定 this 上下文到组件实例。

javascript 复制代码
export default {
  methods: {
    handleClick() {
      console.log(this.someData); // 正确绑定了 this 上下文
    }
  },
  created() {
    this.handleClick(); // 调用方法
  }
}

3. 语法糖

Vue 3 也引入了更多的语法糖,例如 v-model 的改进,可以同时处理多个变量绑定,并支持自定义修改器。此外,通过 <script setup> 标签,Vue 3 提供了一种更声明式的组件写法,极大简化了代码结构。

vue 复制代码
<script setup>
import { ref } from 'vue';

const message = ref('');

// <script setup> 是 Vue 3 中的一个语法糖,使组件的书写更加简洁
</script>

<template>
  <input v-model="message">
</template>

3.1 ref 和 reactive

在 Vue 3 中,ref 和 reactive 是两种基本的响应式引用类型,它们是组合式 API 的核心部分。这两种类型都允许 Vue 跟踪依赖并在数据变化时自动更新 DOM,但它们在使用方式和适用场景上有所不同。

3.1.1 ref

ref 用于定义一个响应式的引用数据类型。使用 ref 可以把基本数据类型(如字符串、数字、布尔值)包装成一个响应式对象。这个对象有一个 .value 属性,用来获取或设置其内部值。

特点
  • 可以用于基本数据类型。
  • 返回一个包含 value 属性的响应式对象。
  • 可以在模板中直接使用,无需通过 .value 访问。
  • 跨组件或模块传递时,保持响应性。
示例
javascript 复制代码
import { ref } from 'vue';

const count = ref(0);

function increment() {
  count.value++;
}

3.1.2 reactive

reactive 用于创建一个响应式的复杂数据对象,如对象或数组。当这些数据对象的属性变化时,reactive 提供的响应式系统会确保视图与数据状态保持同步。

特点
  • 只能用于对象或数组。
  • 返回一个透明代理(Proxy)的响应式版本,直接修改属性即可。
  • 更适合用于构建复杂的响应式结构,如状态存储或大型对象模型。
  • 传递 reactive 对象时,它们的响应性会被保留。
示例
javascript 复制代码
import { reactive } from 'vue';

const state = reactive({
  count: 0,
  items: ['apple', 'banana']
});

function increment() {
  state.count++;
}

主要区别

  1. 数据类型支持 :ref 适用于基本数据类型,而 reactive 适合复杂数据类型(对象或数组)。
  2. 使用方式 :使用 ref 时,需要通过 .value 属性来访问或修改其值;使用 reactive 时,可以直接访问或修改对象的属性,无需额外的属性。
  3. 模板引用 :在模板中使用 ref 时,Vue 会自动展开 .value,让你可以直直接引用;而 reactive 对象的属性可以直接被访问,无需任何额外处理。
  4. 设计意图 :ref 主要用于更简单的场景和跨组件的状态共享;reactive 更适合用来管理较为复杂的状态逻辑或数据结构。

选择使用 ref 或 reactive 应基于具体需求:如果你处理的是基本类型或需要跨组件传递响应式数据,ref 是更好的选择;如果你需要管理一个较大的数据结构,如对象或数组,reactive 更为合适。

4. 箭头函数 VS 函数声明

function xxx() {} 和 const xxx = () => {}

这两种定义函数的方式各有特点和适用场景。这两种方式的主要差异在于函数的作用域、this 绑定、构造函数的能力和提升(hoisting)特性。下面我们详细比较这两种方式,并给出示例。

1. this 绑定

函数声明 (function functionName() {}) 创建的函数拥有自己的 this 上下文,这取决于如何调用该函数。如果作为对象的方法调用,this 指向该对象;如果单独调用,this 指向全局对象(在严格模式下是 undefined)。

箭头函数 (const functionName = () => {}) 不拥有自己的 this 上下文,而是继承自封闭上下文的 this 值,通常称为 "词法作用域"。这使得箭头函数非常适合用作回调函数,特别是在需要访问外部 this 上下文的情况。

示例

javascript 复制代码
const team = {
  members: ['Jane', 'Bill'],
  teamName: 'Super Squad',
  teamSummary: function() {
    // 使用函数声明,这里的 this 指向 team 对象
    return this.members.map(function(member) {
      return `${member} is on team ${this.teamName}`; // 这里的 this 不指向 team 对象,除非使用 bind
    }.bind(this)); // 注意 bind 的使用
  }
};

const teamArrow = {
  members: ['Jane', 'Bill'],
  teamName: 'Super Squad',
  teamSummary: function() {
    // 使用箭头函数,自动捕获上下文中的 this
    return this.members.map(member => `${member} is on team ${this.teamName}`);
  }
};

2. 函数提升

函数声明 在代码执行之前就会被提升,这意味着你可以在声明函数之前调用它。

箭头函数 作为变量声明的一部分,具体到这里是 const 声明,所以它们不会提升。你必须先定义函数,然后才能使用它。

示例

javascript 复制代码
console.log(sum(10, 5)); // 正常工作,因为函数提升
function sum(a, b) {
  return a + b;
}

console.log(add(10, 5)); // 报错:add is not a function
const add = (a, b) => a + b;

3. 用作构造函数

函数声明 可以用作构造函数,与 new 关键字一起使用来创建新对象。

箭头函数 不能用作构造函数,如果尝试这样做会抛出错误。

示例

javascript 复制代码
function Person(name) {
  this.name = name;
}
const person1 = new Person('John'); // 正常工作

const Animal = (name) => {
  this.name = name;
}
const animal1 = new Animal('Dog'); // 报错:Animal is not a constructor
相关推荐
deli00711 分钟前
1 个汉字算几个 token?实测中英文 prompt 与代码的编码差异
前端
无限聚核18 分钟前
抖音 certificate.prepare 之后怎么验券?和美团 msconsume 差在哪,无限聚核
前端·微信小程序
2603_9658966227 分钟前
Grid 网格布局|CSS 二维页面排版体系
前端·css
有味道的男人43 分钟前
搜好货平台关键词商品搜索接口:分页容错与商品数据轻量化提取方案
服务器·前端·javascript
lovingsoft1 小时前
Chrome Lighthouse 详解
前端·chrome
Qlly2 小时前
全栈工程师怎么接需求?从一句「加个功能」聊到能开发、能验收
前端·后端
马可家的菠萝2 小时前
你的微信“文件传输助手”,是不是已经成了第二个网盘?
前端·后端·架构
略略略啦2 小时前
Vibe Coding 基于Spec DD和TDD的实践指南
前端
shmily麻瓜小菜鸡2 小时前
前端实现图片与PDF文字识别敏感信息打码方案
前端·pdf·状态模式
打工仔折腾 AI2 小时前
LangChain 工具调用实战:从 Tool 定义到 Agent 执行链路拆解
java·前端·人工智能·后端·python·langchain·ai agent 实战