skip to Main Content

I have the following ugly pattern:

// defined once
const articleComponents = {
    header: "",
    sections: [], // {title: string, content: string}[]
    footer: ""
};

// ...

function appendSuffix(suffix)
{
    if (/* target header */) {
        if (!articleComponents.header.endsWith(" ")) {
            articleComponents.header += " ";
        }
        articleComponents.header += suffix;
    }
    else if (/* target body */) {
        if (!articleComponents.sections[articleComponents.sections.length - 1].content.endsWith(" ")) {
            articleComponents.sections[articleComponents.sections.length - 1].content += " ";
        }
        articleComponents.sections[articleComponents.sections.length - 1].content += suffix;
    }
    else if (/* target footer */) {
        if (!articleComponents.footer.endsWith(" ")) {
            articleComponents.footer += " ";
        }
        articleComponents.footer += suffix;
    }
}

This is obviously redundant but due to the nature of the += operator for strings, and strings being immutable, it’s hard to simplify this.

Goals

  • Ideally, in each if-statement, the articleComponents.xyz/articleComponents.sections[articleComponents.sections.length - 1].content expression should appear exactly once.
  • articleComponents should not be modified; I rely on its format
    • additional helper objects inside appendSuffix are okay

C++ Counterpart

For clarity, this is how I could write it in C++ (simplified):

void appendSuffix(string_view suffix) {
    string &target = /* target header */ ? articleComponents.header
                   : /* target body */   ? articleComponents.back().content
                   : /* target footer */ ? articleComponents.footer
                   : throw ...;

    if (target.back() != ' ') {
        target += ' ';
    }
    target += suffix;
}

It would be great if I could have something along those lines in JS.

2

Answers


  1. To evade redundancy and simplify the code, you can establish a helper function that accepts the target component and the suffix as parameters. This function can handle the logic of appending the suffix to the relevant component. Here’s an example of how you can refactor your code:

    const articleComponents = {
      header: "",
      body: "",
      footer: ""
    };
    
    function appendSuffix(target, suffix) {
      const component = articleComponents[target];
      
      if (!component.endsWith(" ")) {
        component += " ";
      }
      
      articleComponents[target] = component + suffix;
    }
    
    // Usage example
    appendSuffix("header", "suffix1");
    appendSuffix("body", "suffix2");
    appendSuffix("footer", "suffix3");
    

    By passing the target component ("header", "body", or "footer") and the suffix to the addSuffix function, you eliminate the need for multiple if-else statements and repetitive code. The function retrieves the appropriate component from articleComponents, checks if it ends with a space, and appends the suffix accordingly. The modified component is then assigned back to articleComponents[target].

    This approach allows you to accomplish your goals of reducing repetition and avoiding direct modifications to articleComponents.

    Login or Signup to reply.
  2. How about this one here?

    const articleComponents = {
      header: ' ',
      sections: [{
          title: 's1.title',
          content: 's1.content',
        },
        {
          title: 's2.title',
          content: 's2.content',
        },
        {
          title: 's3.title',
          content: 's3.content',
        }
      ],
      footer: ''
    };
    
    // This could be an enum in TS
    const Target = {
      HEADER: 'HEADER',
      BODY: 'BODY',
      FOOTER: 'FOOTER'
    };
    
    function processString(str, suffix) {
      return !str.endsWith(' ') ? `${str} ${suffix}` : `${str}${suffix}`;
    }
    
    function processSections(sections, suffix) {
      return sections.map((section, idx) => {
        return idx === sections.length - 1 ? {
            ...section,
            content: processString(section.content, suffix)
          } :
          section
      });
    }
    
    function appendSuffix(suffix, target) {
      switch (target) {
        case Target.HEADER:
          return processString(articleComponents.header, suffix);
        case Target.FOOTER:
          return processString(articleComponents.footer, suffix);
        case Target.BODY:
          return processSections(articleComponents.sections, suffix);
        default:
          throw new Error(`Invalid target ${target}!`);
      }
    }
    
    const results = [];
    results.push(appendSuffix('SUFFIX', Target.HEADER));
    results.push(appendSuffix('SUFFIX', Target.BODY));
    results.push(appendSuffix('SUFFIX', Target.FOOTER));
    
    results.forEach((it) => console.log(it));
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search