array return [object Object] on any kind of interaction, if returned from a class why?

Intro

I’m currently trying to get to know how spa commonly work, router, state, route etc,
I’ve done a basic hash router and can display on a fragment element, and now trying to introduce a custom react like component, but arrived to placeholder {{ }} replacement, I’ve been stuck for days on an error which, even if I’ve found a work around, still do not even begin to understand. it seems like if returned from within class constructor i cannot use […].join(“”) or […][1] without it to interpreted as [object Object]

Code & How it happened

In order not to interfere with nested component i settled for a DFS through child Node of my component
and delegated the parsing to a sub class, the specific condition handling that being :

      if (current && current?.getAttribute) {
          current.innerHTML = new _Fo_Component_PlaceholderParser({ node: current, content: current.innerHTML })
      }

in the _Fo_Component_PlaceholderParser


class _Fo_Component_PlaceholderParser {

    constructor({ node, content }) {
         this.node = node;

         return this.placeholderParser(content);
    }

     placeholderParser(value) {
        if(value.trim === "") {
            return value
        }
        
        const parts = value.split(/(</?w+[^>]*>)/g);

        const stack = [];
        let output = [];

        for (let part of parts) {
            const trimmedPart = part.trim();

            if (/^<w+[^>]*>$/.test(trimmedPart)) {
                stack.push(trimmedPart);
                const processedTag =
                    stack.length === 1
                        ? trimmedPart.replace(/{{.*?}}/g, "testing")
                        : trimmedPart;

                output.push(String(processedTag));

                if (this.isSelfClosing(trimmedPart)) {
                    stack.pop();
                }
            } else if (/^</w+>$/.test(trimmedPart)) {
                stack.pop();
                output.push(String(trimmedPart));
            } else if (/{{.*?}}/.test(trimmedPart) && stack.length === 0) {
                output.push(String(trimmedPart.replace(/{{.*?}}/g, "testing")));
            } else if (trimmedPart.length > 0) {
                output.push(String(trimmedPart));
            }
        }

        return output.join("");
    }

//rest of the method ...
}

To come to where my problem pops up, it’s in the _Fo_Component_PlaceholderParser. This class directly returns
this.placeholderParser(), which itself returns output.join("").

Except, on the DOM, output.join("") says [object Object] even though, when logged during the process,
it contains the parsed data that should be returned.

For proof, if instead I return simply output, it shows perfectly as an array in the DOM, comma-separated.

So output.join("") shouldn’t be a problem, right?
And also, it’s not only .join.
If I try output[0], it also says [object Object], so building a string out of output by hand doesn’t work—it’ll just return [object Object] [object Object] [object Object]....

And don’t even think my logic has anything to do with that—I cut it out and replaced output with ["test", "it works"].
It did the exact same thing, even when I did nothing to the array. The values were hardcoded and directly returned, but it behaved the same way. Just why?

What’s happening here?

It only works if I return output directly and do the joining from my DFS condition as:

if (current && current?.getAttribute) {
    current.innerHTML = new _Fo_Component_PlaceholderParser({ node: current, content: current.innerHTML }).join("")
}

What I Need Help With

  1. Why does output.join(“”) return [object Object] in the DOM when returned from the class?
  2. Is this related to how JavaScript handles the return value of a class constructor?
  3. What’s the proper way to fix this issue?