3

I've been doing a lot of templating in JS lately, so I've invariably run across the "evil" with statement.

It makes templates much easier to work with as you don't have to preface your variables with an object.

Hearing that with statements are bad and also that they may cause poor performance, I set out for another solution:

My Solution: Function with a bunch of parameters

Here's my code:

var locals = {
  name : "Matt",
  email : "wahoo@wahoo.com",
  phone : "(555) 555-5555"
};

var keys = [];
var values = [];

for (key in locals) {
  local = locals[key];

  keys.push(key)
  values.push(local);

}

keys = keys.join(',');

var fn = new Function(keys, "**TEMPLATE STUFF**"); // function(name, email, phone) {...}
fn.apply(this, values); // fn("Matt","wahoo@wahoo.com","(555) 555-5555")

Note: these accomplish the exact same thing. Both are abstracted away from anyone so an obnoxiously long parameter list is no biggie.

I'm wondering which one is better: using a with statement or a function with the potential for a crazy number of parameters.

Unless someone has a better solution...?

Thanks! Matt Mueller

Matt
  • 22,224
  • 25
  • 80
  • 116

3 Answers3

1

I find your solution very bloated. It is totally non-trivial, while with is so simple (one line of code which in and of itself has very little cost vs. your object traversal and array instantiations). Moreover, your solution requires a template object ready when making the templating function (to define its parameters), which may prove down the road less flexible in my opinion.

Check out MDC. A well designed template would presumably have little logic and heavy variable references (and if it isn't that way, then it should be!), which makes with the perfect candidate in such a situation, because there should be very few other lookups in the scope of the with.

Any extra performance that may be gained seems like it would be micro-optimisation, although rather than theorise, just perform some benchmarks. http://jsperf.com/with-vs-fn does all the setup code before the benchmark for your version, but performs the with stuff during the function execution, so it's not really fair, although even on the slowest iterations you get an idea of how fast it is; >400,000 ops/sec is the slowest. I doub't you need to render more than 400,000 templates a second...

davin
  • 44,863
  • 9
  • 78
  • 78
  • I definitely agree - my solution is a HUGE hack. It also seems to be the only thing I've found that provides *exactly* the same result as `with()` without the issues with `with()`. I actually really dig `with()` - I think it's really elegant, but I do see the dangers of using it. P.S. - thanks for the link I was looking for a good way of testing JS performance. – Matt Apr 14 '11 at 17:58
  • I also think that the way `with` is used in the template context is safe as it will throw errors if you don't define a variable that could leak to global. It was also just a curiosity things: How many parameters *could* you have in a function? :-) – Matt Apr 14 '11 at 18:01
1

Have you tried a JS templating engine? They are usually very fast, and save you some rendering code.

I'm the author of pure.js which is a bit original, but there are plenty of others available and for any taste.

Mic
  • 24,812
  • 9
  • 57
  • 70
  • Well it's an honor :-D.. I was looking at your templating engine last night - it looks pretty slick, I like that the templates are just plain html. I'm actually pretty happy with a modded version `eco` from Node, that makes the syntax look almost exactly like ruby's templates. I needed to use `with` within that context to get the desired syntax. – Matt Apr 14 '11 at 18:10
  • 1
    Aargh... those Ruby guys who want Javascript acting like Ruby !-) – Mic Apr 15 '11 at 19:55
  • Hahaha. To be honest, I don't know Ruby. I don't think you have to know or love Ruby to appreciate the syntax :-D – Matt Apr 24 '11 at 00:33
0

The problems with with are not performance, they are ambiguity and unpredictable behaviour.

See, for example, Hidden Features of JavaScript?

Community
  • 1
  • 1
Matthew Wilson
  • 3,861
  • 21
  • 14
  • I've been digging around and from what I've read, it does run slower than writing the object out (ie. locals.name vs. name). My guess is because it will try to write it in two places instead of one. I was really wondering.. well, what is faster? – Matt Apr 14 '11 at 18:03
  • I've read that DoU and DoT templating avoids with for this very reason - http://github.com/olado/doT/ – Matt Apr 14 '11 at 18:04