That's a really smart hack, I didn't realize comments were included in the output of Function#toString. You could do other cool things, e.g. an annotation for type checking:
function checkType(f) {
return function(a) {
var type = f.toString().match(/\/\/(.*)\n/)[1].trim();
if(type !== typeof(a)) throw new Error('Invalid type');
return f(a);
}
}
var halve = checkType(function(n) {
// number
return n / 2;
});
halve(4); // returns 2
halve('string'); // emits error
When I was first really to program I was into hacking javascript to do the crazy things I wanted it to do. I basically did exactly this, albeit with a worse interpolation feature[1]. Don't actually do this please. In the browser, just open up a different <script type="text/plain"> and grab the string from that tag. On the server you can just use a file. Any string that's actually long enough for `["foo", "bar"].join("\n")` to be too cumbersome should be in a separate file, especially if the other way involves a massive hack.
Interesting solution. I usually find this type of problem when doing templating in the client when updating things via Ajax. I either use the DOM to store the template or end up concatenating for smaller things.
Since to preserve these comments in minification requires conscious effort, I wonder if there's an alternative that could convert the comments to regular JS before minification. Obviously you can't just run it in Node as normal doing it this way.
I thank you from the bottom of my heart. This drove me crazy when playing around with WebGL and shaders, because for various reasons I didn't want to put those in separate files.
The first problem I see, is using any build process which will remove all the comments. Therefore your string will become ''. I wonder how to avoid this.
Cool hack, but a cleaner solution would be to just use fs.readFileSync if you really want long strings, and let browserify/brfs to inline it for you in the browser.
Using this in a library would be pretty unsafe, given how it's browser-dependent, is prone to issues with minifcation, and could just break with future versions of your JS engine.
At one point the E4X standard (back in 2007?) enabled a cool multi-line string hack by promoting XML elements to language entities. You could say:
var htmlFragment = "" + (<r><![CDATA[
l(a
le
af
fa
ll
s)
one
l
iness
- e.e. cummings
;
]]></r>);
And then `htmlFragment` would contain your multi-line string. (The addition with the empty string coerces the <r> element to output its `toString()` value, which happens to be the innerHTML).
This is largely a historical factoid, though. I don't think browsers beyond Mozilla ended up supporting E4X.
Really clever hack with the function's toString method!
Cool hack but not supporting multiline strings is a feature as far as I'm concerned. Everyone seems to agree that HTML shouldn't contain JavaScript, why should JavaScript contain HTML?
That is actually currently being contested by React and .jsx.
That said, I've seen multiline abused for writing SQL queries as well, which would have been better off being written in a separate .SQL file and `fs.read` into a string with a descriptive var name. (Ignoring that massive SQL strings is a code smell imo).
Yeah, pretty much, but in Node we wrap repetitive things in modules, as they're super cheap. Your snippet is also missing some things like indentation stripping, error handling and browser support.
I just use ES6 template strings together with the es6ify transform for Browserify. Works in all browsers and very likely performs much better than using Function.prototype.toString.
Wouldn't something like a Sweet.js macro be better for this? Just have it output a string with '\n\' at the end of lines, or using Array.join() or whatever you like.
Weird... I just just randomly looking at this a few days ago upon a search for "js multiline" when wondering about the common way to spell multiline (multi line vs multi-line vs multiline). I was intrigued by his code though, ultimately in awe of the cleverness and conciseness of it. Very cool hack! Crazy coincidence to see the very code on HN only a few days later.
[+] [-] mappum|11 years ago|reply
[+] [-] tlrobinson|11 years ago|reply
Probably because sometimes they're not, depending on the JavaScript engine (though perhaps all of the major modern browsers do)
[+] [-] igl|11 years ago|reply
[+] [-] adrusi|11 years ago|reply
[1]: http://zurb.com/forrst/posts/Javascript_native_multi_line_st...
[+] [-] jonpacker|11 years ago|reply
[+] [-] wldlyinaccurate|11 years ago|reply
I think for this reason I still prefer using Array.prototype.join for multiline strings:
[+] [-] gravity13|11 years ago|reply
[+] [-] mofle|11 years ago|reply
See: https://github.com/sindresorhus/multiline#minification
[+] [-] andrey-p|11 years ago|reply
[+] [-] abrkn|11 years ago|reply
[+] [-] martin-adams|11 years ago|reply
Since to preserve these comments in minification requires conscious effort, I wonder if there's an alternative that could convert the comments to regular JS before minification. Obviously you can't just run it in Node as normal doing it this way.
[+] [-] tlrobinson|11 years ago|reply
[+] [-] mofle|11 years ago|reply
[+] [-] mushishi|11 years ago|reply
[+] [-] PavlovsCat|11 years ago|reply
[+] [-] waynecochran|11 years ago|reply
[+] [-] ttty|11 years ago|reply
[+] [-] mofle|11 years ago|reply
[+] [-] criswell|11 years ago|reply
[+] [-] evilpie|11 years ago|reply
Firefox Nightly currently supports just enough of template strings to give you multiline strings.
[+] [-] Excavator|11 years ago|reply
1: https://bugzilla.mozilla.org/show_bug.cgi?id=688857#c22
2: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
3: https://developer.mozilla.org/en-US/docs/Web/JavaScript/ECMA...
[+] [-] mattdesl|11 years ago|reply
Using this in a library would be pretty unsafe, given how it's browser-dependent, is prone to issues with minifcation, and could just break with future versions of your JS engine.
[+] [-] cyphunk|11 years ago|reply
[+] [-] coldtea|11 years ago|reply
Did you even read TFA?
[+] [-] eob|11 years ago|reply
This is largely a historical factoid, though. I don't think browsers beyond Mozilla ended up supporting E4X.
Really clever hack with the function's toString method!
[+] [-] jasonkostempski|11 years ago|reply
[+] [-] biscarch|11 years ago|reply
That said, I've seen multiline abused for writing SQL queries as well, which would have been better off being written in a separate .SQL file and `fs.read` into a string with a descriptive var name. (Ignoring that massive SQL strings is a code smell imo).
[+] [-] andrelaszlo|11 years ago|reply
[+] [-] mofle|11 years ago|reply
[+] [-] jgillich|11 years ago|reply
[+] [-] z3t4|11 years ago|reply
appendChild instead of innerHTML .html file instead of html inside a .js file. .css file instead of css inside a .js file.
It can get very messy if you store "data" inside JS. Especially if you store markup or styling in the JS.
[+] [-] tach4n|11 years ago|reply
[+] [-] chrishawes|11 years ago|reply
[+] [-] teddyh|11 years ago|reply
(And people complain about Python having significant whitespace?)
[+] [-] Kiro|11 years ago|reply
[+] [-] tfb|11 years ago|reply