Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> JavaScript

Cách tìm hàm gọi (caller function) trong JavaScript

Để xác định hàm nào đang gọi hàm hiện tại (caller function) trong JavaScript, cách truyền thống là sử dụng thuộc tính arguments.callee.caller hoặc functionName.caller. Tuy nhiên, đây là tính năng phi chuẩn (non-standard), deprecated (lỗi thời), và bị cấm trong Strict Mode.

⚠️ CẢNH BÁO QUAN TRỌNG

  • Không dùng trong production code. Không thuộc chuẩn ECMAScript.
  • Bị loại bỏ trong Strict Mode ("use strict";) - ném TypeError.
  • Hiệu năng kém (ngăn chặn tối ưu hóa JIT).
  • Không hoạt động với Arrow Function, Class Method, Async Function.

Cách cũ (Chỉ để hiểu legacy code)

function display() {
    // Cách 1: arguments.callee.caller (Deprecated)
    // console.log("Caller (arguments):", arguments.callee.caller);
    
    // Cách 2: functionName.caller (Deprecated)
    console.log("Caller (name.caller):", display.caller);
}

function callerFunc() {
    display();
}

callerFunc(); // Log: function callerFunc() { display(); }

✅ CÁCH HIỆN ĐẠI, AN TOÀN, CHUẨN (Best Practices)

1. Truyền context/function reference như tham số (Explicit)

function processData(data, onComplete) {
    // Xử lý...
    onComplete(result); // Gọi callback rõ ràng
}

function handleResult(result) {
    console.log("Xử lý xong:", result);
}

processData(myData, handleResult); // Rõ ràng ai gọi ai

2. Dùng Error Stack Trace (Debug/Logging)

function getCallerInfo() {
    const stack = new Error().stack;
    // Parse stack trace để lấy tên hàm gọi
    // Format khác nhau giữa browser/Node.js
    return stack;
}

function myFunc() {
    console.log(getCallerInfo());
}

function caller() { myFunc(); }
caller();

3. Sử dụng Console.trace() (Debug trong DevTools)

function targetFunc() {
    console.trace("Đang ở targetFunc, stack trace:");
}
function caller() { targetFunc(); }
caller();

Xem trong Console DevTools: hiển thị đầy đủ call stack có link nhảy đến source.

4. Wrapper/Decorator (AOP - Aspect Oriented Programming)

function withLogging(fn) {
    return function(...args) {
        console.log(`Gọi ${fn.name} từ`, new Error().stack.split("\n")[2].trim());
        return fn.apply(this, args);
    };
}

const loggedFunc = withLogging(function myFunc() { ... });

5. Async/Await + Error Stack (Node.js/Modern Browser)

async function asyncCaller() {
    await asyncTarget();
}

async function asyncTarget() {
    // Lấy stack trace async
    const stack = new Error().stack;
    console.log(stack);
}

So sánh

CáchChuẩn?Strict Mode?Hiệu năngĐộ tin cậyDùng cho
func.caller❌ Không❌ LỗiKémThấpLegacy code only
Truyền callback/context✅ Có✅ OKTốtCaoProduction (Khuyên dùng)
Error().stack⚠️ Non-standard nhưng phổ biến✅ OKTrung bìnhTrung bình (parse phức tạp)Debug, Logging, Monitoring
console.trace()✅ Console API✅ OKTốt (DevTools)CaoDebug thủ công

Kết luận: Đừng dùng function.caller hay arguments.callee.caller. Hãy thiết kế code rõ ràng: truyền callback, dùng Promise/async-await, hoặc dùng console.trace()/Error().stack cho mục đích debug/logging.