Hàm mũi tên trong ECMAScript 6: Cú pháp và cơ chế hoạt động

ECMAScript 6 (ES6) giới thiệu cú pháp hàm mũi tên (Arrow Function), cung cấp cách khai báo hàm ngắn gọn hơn so với phương thức truyền thống. Cấu trúc cơ bản tập trung vào việc lược bỏ từ khóa function và sử dụng toán tử => để nối danh sách tham số với phần thân hàm.

Dưới đây là các biến thể cú pháp thường gặp khi áp dụng:

  • Một tham số duy nhất: thamSố => biểuThức
  • Nhiều tham số: (thamSố1, thamSố2) => biểuThức
  • Thân hàm đa lệnh: thamSố => { lệnh1; lệnh2; return kếtQuả; }
  • Trả về đối tượng: thamSố => ({ key: value })

So với cách khai báo hàm cổ điển như sau:

const tínhTổngCũ = function(sốA, sốB) {
    return sốA + sốB;
};

function trừCũ(sốA, sốB) {
    return sốA - sốB;
}

Thì cú pháp mũi tên sẽ được viết lại một cách tối giản:

const tínhTổngMới = (sốA, sốB) => {
    return sốA + sốB;
};

// Dạng biểu thức ẩn danh không tên
const phépTrừ = (x, y) => x - y;

Quy tắc đặt ngoặc đơn cho tham số khá rõ ràng: bắt buộc phải có khi không truyền tham số nào hoặc khi có từ hai tham số trở lên. Trường hợp chỉ duy nhất một tham số, ngoặc đơn có thể lược bỏ để mã nguồn gọn nhẹ hơn. Cú pháp này cũng hỗ trợ hoàn toàn spread operator cho số lượng tham số động.

// Không tham số
const khởiTạo = () => console.log('Sẵn sàng');

// Một tham số
const nhânBảy = giáTrị => giáTrị * 7;

// Nhiều tham số & tham số động
const tổngHợp = (x, y, ...phầnCònLại) => x + y;

Hàm mũi tên hoạt động tương đương với hàm ẩn danh nhưng được tối ưu hóa về độ dài dòng code. Nó hỗ trợ hai chế độ trả về kết quả:

  1. Trả về ngầm định: Chỉ áp dụng khi thân hàm gồm duy nhất một biểu thức. Khi đó, hệ thống sẽ tự động trả về kết quả tính toán mà không cần khai báo return hay dấu ngoặc nhọn {}.
  2. Trả về rõ ràng: Khi cần thực hiện nhiều thao tác, khai báo biến trung gian hoặc điều kiện rẽ nhánh, bắt buộc phải sử dụng khối lệnh {} kèm theo câu lệnh return.
() => 'Xin chào hệ thống';
(x, y) => x * y;
z => {
    const kếtQuả = z + 10;
    return kếtQuả;
};

Một điểm cần lưu ý quan trọng là việc trả về đối tượng JavaScript trong chế độ biểu thức đơn. Nếu chỉ đặt dấu ngoặc nhọn {} ngay sau =>, trình thông dịch sẽ nhầm lẫn đó là khối lệnh thay vì định nghĩa đối tượng. Để tránh lỗi cú pháp, phải bao bọc đối tượng bằng cặp dấu ngoặc đơn ().

id => { userId: id }   // Gây lỗi SyntaxError do xung đột với khối lệnh
id => ({ userId: id }) // Đúng cú pháp: ngoặc đơn bọc đối tượng

Cơ chế liên kết ngữ cảnh this

Khác biệt cốt lõi giữa hàm mũi tên và hàm truyền thống nằm ở cách xử lý ngữ cảnh thực thi this. Hàm mũi tên không tự tạo ra ngữ cảnh this riêng cho chính nó. Thay vào đó, nó kế thừa trực tiếp giá trị this từ khối mã bao bọc phía ngoài (lexical scoping). Do thiếu cơ chế ràng buộc ngữ cảnh động, loại hàm này không thể được sử dụng để khởi tạo đối tượng thông qua từ khóa new.

Khi nhúng hàm mũi tên vào bên trong một đối tượng, this sẽ không còn trỏ đến đối tượng đang chứa nó, mà sẽ hướng về ngữ cảnh toàn cục hoặc phạm vi định nghĩa ban đầu. Ví dụ minh họa dưới đây làm rõ sự chênh lệch này:

const tênMôiTrường = 'GlobalScope';

const hệThống = {
    tênMôiTrường: 'ObjectScope',
    thôngBáoMũiTên: () => {
        console.log(this.tênMôiTrường);
    },
    thôngBáoThường() {
        console.log(this.tênMôiTrường);
    }
};

hệThống.thôngBáoMũiTên(); // In ra: GlobalScope
hệThống.thôngBáoThường(); // In ra: ObjectScope

Thẻ: ECMAScript 6 JavaScript Arrow Function Ngữ cảnh this Hàm ẩn danh

Đăng vào ngày 1 tháng 6 lúc 03:35