Refactor

**not ready for merge**

Another round of refactoring and tweaks, focusing on performance in particular. There's some low-hanging fruit, e.g. attributes currently use `fragment.getValue()` instead of `fragment.toString()` (which is a good deal faster) regardless of whether they care about whether the value is stringified.

Also, it turns out that ES6 `let` and default parameters can cause problems. I can't quite isolate the conditions under which this happens, but 6to5 will sometimes transpile functions that use them by wrapping the body in an IIFE *inside* the function. That's obviously not great for performance. My recommendation is that we **avoid `let` and default parameters**, unless we're certain that they will get transpiled sensibly in a given case.