What are the actual uses of ES6 Raw String Access?

Venkat.R picture Venkat.R · Jan 13, 2016 · Viewed 15.2k times · Source

What are the actual uses of String.raw Raw String Access introduced in ECMAScript 6?

// String.raw(callSite, ...substitutions)

function quux (strings, ...values) {
    strings[0] === "foo\n"
    strings[1] === "bar"
    strings.raw[0] === "foo\\n"
    strings.raw[1] === "bar"
    values[0] === 42
}

quux `foo\n${ 42 }bar`

String.raw `foo\n${ 42 }bar` === "foo\\n42bar"

I went through the below docs.

http://es6-features.org/#RawStringAccess

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/raw

http://www.2ality.com/2015/01/es6-strings.html

https://msdn.microsoft.com/en-us/library/dn889830(v=vs.94).aspx

The only the thing that I understand, is that it is used to get the raw string form of template strings and used for debugging the template string.

When this can be used in real time development? They were calling this a tag function. What does that mean?

What concrete use cases am I missing?

Answer

T.J. Crowder picture T.J. Crowder · Aug 7, 2016

The best, and very nearly only, use case for String.raw I can think of is if you're trying to use something like Steven Levithan's XRegExp library that accepts text with significant backslashes. Using String.raw lets you write something semantically clear rather than having to think in terms of doubling your backslashes, just like you can in a regular expression literal in JavaScript itself.

For instance, suppose I'm doing maintenance on a site and I find this:

var isSingleUnicodeWord = /^\w+$/;

...which is meant to check if a string contains only "letters." Two problems: A) There are thousands of "word" characters across the realm of human language that \w doesn't recognize, because its definition is English-centric; and B) It includes _, which many (including the Unicode consortium) would argue is not a "letter."

So if we're using XRegExp on the site, since I know it supports \pL (\p for Unicode categories, and L for "letter"), I might quickly swap this in:

var isSingleUnicodeWord = XRegExp("^\pL+$"); // WRONG

Then I wonder why it didn't work, facepalm, and go back and escape that backslash, since it's being consumed by the string literal.

Easy enough in that simple regex, but in something complicated, remembering to double all those backslashes is a maintenance pain. (Just ask Java programmers trying to use Pattern.)

Enter String.raw:

let isSingleUnicodeWord = XRegExp(String.raw`^\pL+$`);

Example:

let isSingleUnicodeWord = XRegExp(String.raw`^\pL+$`); // L: Letter
console.log(isSingleUnicodeWord.test("Русский"));      // true
console.log(isSingleUnicodeWord.test("日本語"));        // true
console.log(isSingleUnicodeWord.test("العربية"));      // true
console.log(isSingleUnicodeWord.test("foo bar"));      // false
<script src="https://cdnjs.cloudflare.com/ajax/libs/xregexp/3.1.1/xregexp-all.min.js"></script>

Now I just kick back and write what I mean. I don't even really have to worry about ${...} constructs used in template literals to do substitution, because the odds of my wanting to apply a quantifier {...} to the end-of-line assertion ($) are...low. So I can happily use substitutions and still not worry about backslashes. Lovely.


Having said that, though, if I were doing it a lot, I'd probably want to write a function and use a tagged template instead of String.raw itself. But it's surprisingly awkward to do correctly:

// My one-time tag function
function xrex(strings, ...values) {
  let raw = strings.raw;
  let max = Math.max(raw.length, values.length);
  let result = "";
  for (let i = 0; i < max; ++i) {
    if (i < raw.length) {
      result += raw[i];
    }
    if (i < values.length) {
      result += values[i];
    }
  }
  console.log("Creating with:", result);
  return XRegExp(result);
}

// Using it, with a couple of substitutions to prove to myself they work
let category = "L";                                // L: Letter
let maybeEol = "$";
let isSingleUnicodeWord = xrex`^\p${category}+${maybeEol}`;
console.log(isSingleUnicodeWord.test("Русский"));  // true
console.log(isSingleUnicodeWord.test("日本語"));    // true
console.log(isSingleUnicodeWord.test("العربية"));  // true
console.log(isSingleUnicodeWord.test("foo bar"));  // false
<script src="https://cdnjs.cloudflare.com/ajax/libs/xregexp/3.1.1/xregexp-all.min.js"></script>

Maybe the hassle is worth it if you're using it in lots of places, but for a couple of quick ones, String.raw is the simpler option.