You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现可在其他函数内调用的函数及链式调用结构?

Hey there! Let's break down your two requirements step by step with practical, runnable examples that you can adapt for your code.


1. Writing Functions That Can Be Called Inside Another Function (Nested/Internal Functions)

Internal functions are perfect for encapsulating helper logic, avoiding global scope pollution, and leveraging closures to access variables from the outer function. Here are two common use cases:

Case 1: Helper Functions Called Directly Inside the Parent Function

Use this pattern when you need a dedicated utility function only relevant to the parent's logic:

function calculateOrderTotal(items, discountPercentage) {
  // Internal helper: calculates discounted price for a single item
  function applyDiscount(price, discount) {
    return price * (1 - discount / 100);
  }

  let total = 0;
  items.forEach(item => {
    total += applyDiscount(item.price, discountPercentage);
  });
  return total;
}

// Usage example
const cart = [{name: "Wireless Headphones", price: 200}, {name: "Charger", price: 30}];
console.log(calculateOrderTotal(cart, 15)); // Output: 195.5

Note: applyDiscount is only accessible inside calculateOrderTotal—it’s hidden from the global scope, keeping your code clean.

Case 2: Returning Internal Functions (Leveraging Closures)

This pattern lets you create functions that retain access to the parent function’s variables even after the parent has finished executing:

function createUserGreeting(username) {
  // Internal function that remembers the username
  return function(greetingMessage) {
    return `${greetingMessage}, ${username}!`;
  };
}

// Usage example
const greetAlice = createUserGreeting("Alice");
console.log(greetAlice("Good morning")); // Output: "Good morning, Alice!"
console.log(greetAlice("Welcome back")); // Output: "Welcome back, Alice!"

Here, the returned internal function maintains access to the username variable long after createUserGreeting has run—that’s the power of closures.


2. Building a Chainable Call Structure

Chainable calls work by having each method return the current object (or a related object) after execution, allowing you to chain method calls one after another. Let’s build the exact structure you mentioned: require("Promotions").getDisounts().getProductDiscounts().getLength();

Option 1: Simple Object Literal (Best for Lightweight Modules)

// Promotions.js
module.exports = {
  // Step 1: Fetch all discounts
  getDisounts() {
    // Simulate fetching discount data
    this.allDiscounts = [
      {type: "product", value: 10},
      {type: "category", value: 15},
      {type: "product", value: 5},
      {type: "product", value: 20}
    ];
    return this; // Return the current object to enable chaining
  },

  // Step 2: Filter to only product-specific discounts
  getProductDiscounts() {
    if (!this.allDiscounts) throw new Error("Call getDisounts() first!");
    this.productDiscounts = this.allDiscounts.filter(d => d.type === "product");
    return this; // Return the current object again
  },

  // Step 3: Get the count of product discounts
  getLength() {
    if (!this.productDiscounts) throw new Error("Call getProductDiscounts() first!");
    return this.productDiscounts.length;
  }
};

Usage:

const promotions = require("./Promotions");
const productDiscountCount = promotions.getDisounts().getProductDiscounts().getLength();
console.log(productDiscountCount); // Output: 3

Option 2: Class-Based Structure (Best for Complex, Reusable Instances)

If you need multiple independent instances of your Promotions module, use a class:

// Promotions.js
class Promotions {
  getDisounts() {
    this.allDiscounts = [
      {type: "product", value: 10},
      {type: "category", value: 15},
      {type: "product", value: 5}
    ];
    return this;
  }

  getProductDiscounts() {
    if (!this.allDiscounts) throw new Error("Call getDisounts() first!");
    this.productDiscounts = this.allDiscounts.filter(d => d.type === "product");
    return this;
  }

  getLength() {
    if (!this.productDiscounts) throw new Error("Call getProductDiscounts() first!");
    return this.productDiscounts.length;
  }
}

// Export a singleton instance (or export the class to let users instantiate their own)
module.exports = new Promotions();

The usage remains identical to the object literal version.


内容的提问来源于stack exchange,提问作者Maxim Kuželj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:25:58