ECMAScript 2015–2023: Các tính năng cốt lõi nâng cao cho ứng dụng Vue

ECMAScript (ES) là tiêu chuẩn ngôn ngữ kịch bản do tổ chức Ecma International ban hành, làm nền tảng cho JavaScript và nhiều môi trường thực thi hiện đại. Mỗi phiên bản ES — từ ES2015 (ES6) đến các bản cập nhật gần đây như ES2022 và ES2023 — đều giới thiệu các cải tiến về cú pháp, khả năng biểu đạt và xử lý dữ liệu, đặc biệt hữu ích trong phát triển ứng dụng Vue dựa trên Composition API hoặc Options API.

1. Khai báo biến có phạm vi rõ ràng

Thay vì var, các từ khóa letconst đảm bảo phạm vi khối (block-scoped) và ngăn ghi đè vô tình. Trong Vue, điều này giúp kiểm soát trạng thái cục bộ trong hàm setup() hoặc phương thức lifecycle một cách an toàn:

export default {
  setup() {
    const baseURL = 'https://api.example.com';
    let retryCount = 0;

    const fetchWithRetry = async (path) => {
      try {
        const res = await fetch(`${baseURL}${path}`);
        return await res.json();
      } catch (err) {
        if (retryCount < 2) {
          retryCount++;
          return fetchWithRetry(path);
        }
        throw err;
      }
    };

    return { fetchWithRetry };
  }
};

2. Hàm mũi tên và bối cảnh this

Hàm mũi tên không ràng buộc riêng this, nên phù hợp khi dùng trong callback hoặc xử lý sự kiện mà cần giữ bối cảnh hiện tại — ví dụ khi kết nối với store Pinia hoặc quản lý trạng thái phản ứng:

import { ref } from 'vue';

export default {
  setup() {
    const loading = ref(false);
    const items = ref([]);

    const loadItems = async () => {
      loading.value = true;
      try {
        const data = await fetch('/api/items').then(r => r.json());
        items.value = data.map(item => ({
          ...item,
          createdAt: new Date(item.timestamp)
        }));
      } finally {
        loading.value = false;
      }
    };

    // Dùng arrow function để tránh mất `loading`, `items` khi gọi trong setTimeout hoặc event handler
    const delayedLoad = () => setTimeout(() => loadItems(), 300);

    return { items, loading, delayedLoad };
  }
};

3. Chuỗi mẫu và biểu thức nhúng

Chuỗi mẫu (`...${expression}...`) hỗ trợ đa dòng và chèn giá trị động — đặc biệt tiện lợi khi xây dựng template động hoặc log thông tin debug trong component:

<template>
  <div class="user-card">
    <h2>{{ `Người dùng: ${user.name}` }}</h2>
    <p>Tuổi: {{ user.age }} – Cập nhật lúc {{ new Date().toLocaleTimeString() }}</p>
  </div>
</template>

4. Giải cấu trúc dữ liệu

Giải cấu trúc giúp trích xuất nhanh thuộc tính từ đối tượng hoặc phần tử từ mảng — thường dùng khi nhận props, xử lý response từ API hoặc khai báo state với reactive:

import { reactive } from 'vue';

export default {
  props: {
    userInfo: {
      type: Object,
      required: true
    }
  },
  setup(props) {
    const { name, email, preferences } = props.userInfo;
    const { theme = 'light', notifications = true } = preferences || {};

    const formState = reactive({
      name,
      email,
      theme,
      notifications
    });

    return { formState };
  }
};

5. Xử lý bất đồng bộ với async/await

Từ ES2017, async/await thay thế Promise chain bằng cú pháp tuần tự, dễ đọc hơn — rất phổ biến trong các hàm gọi API trong onMounted hoặc composable:

import { onMounted } from 'vue';
import { useQuery } from '@tanstack/vue-query';

export default {
  setup() {
    const { data, isLoading } = useQuery({
      queryKey: ['posts'],
      queryFn: async () => {
        const res = await fetch('/api/posts?limit=10');
        if (!res.ok) throw new Error('Failed to fetch posts');
        return res.json();
      }
    });

    onMounted(async () => {
      console.log(`Đã tải ${data.value?.length || 0} bài viết`);
    });

    return { data, isLoading };
  }
};

6. Lớp và kế thừa kiểu OOP

Mặc dù Vue khuyến khích lập trình hàm và phản ứng, lớp vẫn được sử dụng để đóng gói logic nghiệp vụ tái sử dụng — ví dụ mô hình dữ liệu hoặc service client:

class APIClient {
  constructor(base = '/api') {
    this.base = base;
  }

  async request(endpoint, options = {}) {
    const url = `${this.base}${endpoint}`;
    const config = {
      headers: { 'Content-Type': 'application/json', ...options.headers },
      ...options
    };
    const res = await fetch(url, config);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    return res.json();
  }
}

// Sử dụng trong composable
export function useUserAPI() {
  const client = new APIClient('/api/users');

  const getUser = (id) => client.request(`/${id}`);
  const updateUser = (id, payload) => client.request(`/${id}`, { method: 'PUT', body: JSON.stringify(payload) });

  return { getUser, updateUser };
}

7. Hệ thống module tĩnh

Các câu lệnh importexport cho phép chia nhỏ logic thành các file độc lập — thiết yếu khi xây dựng thư viện composable hoặc phân tách store:

// composables/useAuth.js
export function useAuth() {
  const token = ref('');
  const isAuthenticated = computed(() => !!token.value);

  const login = async (credentials) => {
    const res = await fetch('/auth/login', {
      method: 'POST',
      body: JSON.stringify(credentials)
    });
    token.value = (await res.json()).token;
  };

  return { token, isAuthenticated, login };
}

// Trong component
import { useAuth } from '@/composables/useAuth';

8. Toán tử mở rộng (...) trong thực tiễn Vue

Toán tử mở rộng giúp sao chép, kết hợp và chuyển đổi dữ liệu linh hoạt — đặc biệt hữu ích khi làm việc với props, emit, hoặc tạo bản sao phản ứng:

// Gộp props và thêm thuộc tính mới
const enhancedProps = {
  ...$props,
  isInteractive: true,
  timestamp: Date.now()
};

// Tạo bản sao reactive không ảnh hưởng gốc
const editableUser = reactive({ ...user.value });

// Truyền mảng vào v-for hoặc props
const allPermissions = [...basePermissions, ...extraPermissions];

Thẻ: ECMAScript es6 es2022 Vue3 composition-api

Đăng vào ngày 6 tháng 8 lúc 21:01