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

JavaScript函数间变量共享及重复功能代码简化方案咨询

Simplifying Duplicate JavaScript Function Logic & Sharing Variables

Great question! Let's break this down clearly—you don't need to jump straight to classes to fix this repetition, and there are several clean, flexible ways to simplify your code and share variables between functions.

Do You Need Classes? Nope—Here Are Better Alternatives

Your two functions have tons of repeated code (DOM selections, Stripe setup, font/style config) — classes work, but composition (building functionality from shared pieces) is often lighter and more flexible for this kind of scenario. Let’s start with the simplest fixes:

1. Extract Shared Logic into Reusable Functions

First, pull out all the repeated code into standalone utility functions. This way, you only write it once, and both CreditCard and DirectDebit can reuse it.

// Get all shared DOM/configuration values in one place
function getSharedPaymentSettings() {
  const stripeKeyTag = document.querySelector('meta[name=stripe-publishable-key]');
  const serverConstants = document.querySelector('#server_side_constants');
  
  // Exit early if critical elements are missing
  if (!stripeKeyTag || !serverConstants) return null;

  return {
    stripeKey: stripeKeyTag.getAttribute('content'),
    fontName: serverConstants.getAttribute('data-font-name'),
    fontColor: serverConstants.getAttribute('data-font-color'),
    fontSource: serverConstants.getAttribute('data-font-source'),
    locale: document.querySelector('html').getAttribute('lang'),
    errorElement: document.querySelector('#stripe_error_message'),
    clientSecret: document.querySelector('#client_secret'),
    submitButton: document.querySelector('input[type=submit]'),
    spinner: document.querySelector('#spinner'),
    nameField: document.querySelector('#name'),
    emailField: document.querySelector('#email')
  };
}

// Initialize Stripe and elements with shared config
function initSharedStripe(settings) {
  if (!settings) return null;
  
  const stripe = Stripe(settings.stripeKey);
  const elements = stripe.elements({
    fonts: [{ family: settings.fontName, src: settings.fontSource }],
    locale: settings.locale
  });
  const baseStyle = { base: { fontFamily: settings.fontName, color: settings.fontColor } };

  return { stripe, elements, baseStyle };
}

Now refactor your original functions to use these utilities:

function CreditCard() {
  const sharedSettings = getSharedPaymentSettings();
  if (!sharedSettings) return;

  const { stripe, elements, baseStyle } = initSharedStripe(sharedSettings);
  const form = document.querySelector('#credit_card_form');
  if (!form) return;

  // Add your CreditCard-specific logic here
  // ...
}

function DirectDebit() {
  const sharedSettings = getSharedPaymentSettings();
  if (!sharedSettings) return;

  const { stripe, elements, baseStyle } = initSharedStripe(sharedSettings);
  const form = document.querySelector('#direct_debit_form');
  if (!form) return;

  // DirectDebit-specific value (only needed here)
  const country = document.querySelector('#server_side_constants').getAttribute('data-country');

  // Add your DirectDebit-specific logic here
  // ...
}

2. Use Factory Functions for Even More Encapsulation

If you want to wrap shared and specific logic together, factory functions (functions that return other functions/objects) are a great fit. They let you reuse shared setup while keeping each payment method’s unique logic separate:

// Factory function to create payment processors
function createPaymentProcessor(formSelector, getExtraSettings = () => {}) {
  return function() {
    const sharedSettings = getSharedPaymentSettings();
    if (!sharedSettings) return;

    const { stripe, elements, baseStyle } = initSharedStripe(sharedSettings);
    const form = document.querySelector(formSelector);
    if (!form) return;

    // Get any method-specific settings
    const extraSettings = getExtraSettings(sharedSettings);

    // Run method-specific initialization
    if (form.id === 'credit_card_form') {
      initCreditCard({ stripe, elements, baseStyle, form, sharedSettings });
    } else if (form.id === 'direct_debit_form') {
      initDirectDebit({ stripe, elements, baseStyle, form, sharedSettings, ...extraSettings });
    }
  };
}

// Specific initialization functions
function initCreditCard({ stripe, elements, baseStyle, form }) {
  // CreditCard-only logic here
  // ...
}

function initDirectDebit({ stripe, elements, baseStyle, form, country }) {
  // DirectDebit-only logic here (uses country)
  // ...
}

// Create your payment processor functions
const CreditCard = createPaymentProcessor('#credit_card_form');
const DirectDebit = createPaymentProcessor('#direct_debit_form', () => {
  return { country: document.querySelector('#server_side_constants').getAttribute('data-country') };
});

How to Share Variables Between Functions

You’ve already seen one way (via shared config objects), but here are the most common, clean approaches:

  • Shared Config Functions: As we did above, use functions like getSharedPaymentSettings() to return a single object of shared values. All functions can call this to access the same data.
  • Module-Level Closures: If you’re using ES modules (or an IIFE for older code), you can define variables inside the module that only your payment functions can access. This avoids polluting the global scope:
    // Inside a module or IIFE
    let cachedStripeInstance = null;
    
    function initSharedStripe(settings) {
      if (!cachedStripeInstance) {
        cachedStripeInstance = Stripe(settings.stripeKey);
      }
      // ... rest of initialization
    }
    
    Now both CreditCard and DirectDebit will reuse the same Stripe instance instead of creating a new one.
  • Pass Shared Objects as Arguments: If you need to pass dynamic shared data, pass an object to your functions instead of defining it globally. This keeps dependencies explicit.

When Should You Use Classes?

Classes are fine if you need to create multiple instances of a payment processor with state (like tracking form submission status), but for your current scenario, composition with utility/factory functions is simpler and avoids over-engineering.

内容的提问来源于stack exchange,提问作者Tintin81

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 20:02:44