views:

75

answers:

3

How might this be improved, as it pertains to the loop and the regex replace?

var properties = { ... };
var template = element.innerHTML;

for (var name in properties) {
    template = template.replace
        (new RegExp('\\${' + name + '}', 'gm'), properties[name]);
}

element.innerHTML = template;

Is there a way I could get all the matches for /\$\{\w+\}/gm and just use those to build a new string once for the entire operation?

A: 

Inefficient as it seems, I don't think you're going to do much better than that. So long as you're not replacing more than a few dozen tokens, I'd be surprised if this was actually a bottleneck.

If your profiler hasn't identified this as being a bottleneck, I definitely wouldn't spend time rewriting it. If nothing else, it's a lot more readable than your other idea, and in the end it's probably just as fast.

Jason Kester
+1  A: 

I'll bite ;-)

var properties = { ... };
var template = element.innerHTML;
element.innerHTML = template.replace (
    RegExp ('\\$\\{(' + getTags (properties).join ('|') +')\\}'),
    function (m0, tag) {return properties[tag];});

function getTags (obj) {
  var tags = [];
  for (var t in obj)
    hasOwnProperty (t) && tags.push (t);
  return tags;
}

Still loops through the tags of properties (in call on getTags) but creates only one regexp object and scans the template only once.

Note that the tags names in properties should not contain special regexp characters (like . or (etc.).

I'd agree with Jason though, probably not worth the effort unless there are lots of tags or the template is very large.

Hans B PUFAL
+3  A: 

I agree with Jason and Hans WRT not bothering with this from a performance perspective.

But, i would have written it differently in the first place:

element.innerHTML
  = template.replace(/[$][{](\w+)[}]/g, function(x,y){return properties[y]||x;})

Some things to keep in mind

  1. If at all possible, you want to avoid looping over the creation of a RegExp for each iteration. Compiling them is generally considered costly. Or even generalize that to any object creation. Though not at the cost of readability/maintainability.
  2. If you're creating RegExp dynamically, be sure the result is a RegExp, otherwise see #1 as you'll likely be able to apply it.
nicerobot
I don't understand the function(x,y) part. The second parameter for RegEx() is the flags for the pattern, and the second parameter for replace() is the new string that returns.
JamesBrownIsDead
the second parameter for replace is optionally a transformation function
Jimmy
you might want to return properties[y] || y; if you want to keep any symbols that aren't recognized
Jimmy
@JamesBrown: the RegExp was broken. The idea is sound though. @Jimmy: good idea...
Shog9
@Jimmy: ...or maybe `return properties[y] || x;` to restore the full `${foo}` sequence if there's no `foo` property. It effectively ignores invalid tags, which is what the OP's code does (and Hans's code does, too).
Alan Moore
I like the `||x` idea. Good call. The regex originally posted was correct (in rhino 1.7 at least). Also, i edited it to use character classes (like my original) instead of escapes. See my edit comment for my reasoning.
nicerobot
Comment makes sense, hadn't thought of it that way - it is somewhat easier to read this way. Not sure how the original code would have worked though, since \w would still need to be written \\w in a JS string.
Shog9
Agreed. I don't have my edits any more but i suspect i was testing with //g since i generally always use that instead of RegExp('') and i just directly converted it to the RegExp('') when posting it to make it more closely resemble the OP. Anyway ... :)
nicerobot