如何实现函数属性的内外访问?求暴露fetchMovies的requestId简洁方案
Great question! It’s super common to want a function to hold internal state (like your requestId) that’s accessible both inside the function and externally, without messy workarounds. Let’s break down a few elegant solutions depending on your use case:
1. Attach Properties Directly to the Function Object
Since functions in JavaScript are just objects, you can assign properties directly to the function itself. This is perfect if you only need a single shared instance of requestId:
function fetchMovies() { // Assign requestId directly to the function object fetchMovies.requestId = Math.random().toString(36).slice(2); // Use requestId internally console.log(`Initiating request with ID: ${fetchMovies.requestId}`); // Simulate async movie fetch return new Promise(resolve => { setTimeout(() => { resolve([{ id: 1, title: "Blade Runner" }, { id: 2, title: "Dune" }]); }, 1000); }); } // Access requestId externally after calling the function fetchMovies(); console.log(fetchMovies.requestId); // Logs the generated request ID
Pros: Dead simple, no extra wrapping needed—your function stays a function.
Gotcha: The requestId is shared across all calls, so subsequent calls will overwrite it. Use this if you only care about the most recent request’s ID.
2. Closure-Based Module for Isolated Instances
If you need multiple independent instances (each with their own requestId), use a closure to encapsulate state and expose both the function and the property:
function createMovieFetcher() { let requestId; // Private state function fetchMovies() { requestId = Math.random().toString(36).slice(2); console.log(`Starting request with ID: ${requestId}`); return new Promise(resolve => { setTimeout(() => { resolve([{ id: 1, title: "Blade Runner" }, { id: 2, title: "Dune" }]); }, 1000); }); } // Expose the function and a getter for requestId return { fetchMovies, get requestId() { return requestId; // Read-only access from outside } }; } // Create an instance const movieFetcher = createMovieFetcher(); movieFetcher.fetchMovies(); console.log(movieFetcher.requestId); // Gets this instance's request ID // Create another isolated instance const anotherFetcher = createMovieFetcher(); anotherFetcher.fetchMovies(); console.log(anotherFetcher.requestId); // Different ID from the first instance
Pros: Each instance has its own isolated state. Using a getter ensures external code can’t accidentally modify requestId (unless you want it to—just expose the property directly instead).
Use case: When you need multiple separate fetchers that don’t interfere with each other.
3. ES6 Class for Structured State Management
If your logic grows more complex (multiple methods, additional state), a class makes the structure explicit and easy to maintain:
class MovieFetcher { constructor() { this.requestId = null; // Instance-level state } fetchMovies() { this.requestId = Math.random().toString(36).slice(2); console.log(`Request ID: ${this.requestId}`); return new Promise(resolve => { setTimeout(() => { resolve([{ id: 1, title: "Blade Runner" }, { id: 2, title: "Dune" }]); }, 1000); }); } } // Usage const fetcher = new MovieFetcher(); fetcher.fetchMovies(); console.log(fetcher.requestId); // Access the instance's requestId
Pros: Clear, object-oriented structure. Easy to add more methods or state properties as needed.
Use case: When your fetch logic has multiple related operations or needs to scale.
Which One to Choose?
- Go with function object properties for simple, single-instance scenarios.
- Use the closure module for isolated, independent instances with read-only state.
- Opt for a class when you need a structured, scalable solution with multiple methods/state.
内容的提问来源于stack exchange,提问作者David

