Is it possible to have a comment inside a es6 Template-String?

☆樱花仙子☆ 提交于 2019-12-18 14:50:14

问题


Let's say we have a multiline es6 Template-String to describe e.g. some URL params for a request:

const fields = `
    id,
    message,
    created_time,
    permalink_url,
    type
`;

Is there any way to have comments inside that backtick Template-String? Like:

const fields = `
    // post id
    id,
    // post status/message
    message,
    // .....
    created_time,
    permalink_url,
    type
`;

回答1:


No.

That syntax is valid, but will just return a string containing \n// post id\nid, rather than removing the comments and creating a string without them.

If you look at §11.8.6 of the spec, you can see that the only token recognized between the backtick delimiters is TemplateCharacters, which accepts escape sequences, line breaks, and normal characters. In §A.1, SourceCharacter is defined to be any Unicode point (except the ones excluded in 11.8.6).




回答2:


Option 1: Interpolation

We can create interpolation blocks that return an empty string, and embed the comments inside them.

const fields = `
  id, ${ /* post id */'' }
  message, ${ /* post status/message */'' }
  created_time,
  permalink_url,
  type
`;

console.log(fields);

Option 2: Tagged Templates

Using tagged templates we can clear the comments and reconstruct the strings. Here is a simple commented function that uses Array.map(), String.replace(), and a regex expression (which needs some work) to clear comments, and return the clean string:

const commented = (strings, ...values) => {
  const pattern = /\/{2}.+$/gm; // basic idea

  return strings
    .map((str, i) => 
      `${str}${values[i] !== undefined ? values[i] : ''}`)
    .join('')
    .replace(pattern, '');
};

const d = 10;
const fields = commented`
  ${d}
  id, // post ID
  ${d}
  message, // post/status message
  created_time, // ...
  permalink_uri,
  type
`;

console.log(fields);



回答3:


I know it's an old answer, but seeing the answers above I feel compelled to both answer the pure question, and then to answer the spirit of the asker's question.

Can you use comments in template literal strings?

Yes. Yes you can. But it's not pretty.

const fields = `
    id, ${/* post ID */''}
    message, ${/* post/status message */''}
    created_time, ${/*... */''}
    permalink_url,
    type
`;

Note that you have to put '' (an empty string) in the ${ } braces so that Javascript has an expression to insert. Not doing so will result in a runtime error. The quotes can go anywhere outside of the comment.

I'm not a huge fan of this. It's pretty ugly and makes commenting cumbersome, nevermind that toggling comments becomes difficult in most IDEs.

Personally, I use template strings wherever possible, as they are a fraction more efficient than regular Strings, and they capture literally all the text you want, mostly without escaping. You can even put function calls in there!

The string in the example above will be a little odd, and potentially useless for what you're looking for, however, as there will be an initial line-break, extra space between the comma and the comment, as well as an extra final line-break. Removing that unwanted space could be a small performance hit. You could use a regex for that, for speed and efficiency, though... more on that below...

.

Now to answer the intent of the question:

How do I write a comma-delimited list string, with comments on every line?

const fields = [
    "id", // post ID
    "message", // post/status message
    "created_time", //...
    "permalink_url",
    "type"
].join(",\n");

Joining an Array is one way... (as suggested by @jared-smith )

However, in this case, you are creating an array and then immediately discarding the organized data when you only assign the return value of the join() function. Not only that, but you are creating a memory pointer for each string in the array, which won't be garbage collected till end of scope. In that case, it might be more useful to capture the array, joining on the fly as use dictates, or to use a template literal and differently comment your implementation, like ghostDoc style.

It seems that you are only using template literals in order to satisfy a desire to not have quote marks on each line, minimizing cognitive dissonance between the 'string' query parameters as they look in the url and the code. You should be aware that this preserves line breaks, and I doubt you want that. Consider instead:

/****************
 * Fields:
 *   id : post ID
 *   message : post/status message
 *   created_time : some other comment...
 */
const fields = `
    id,
    message,
    created_time,
    permalink_uri,
    type
`.replace(/\s/g,'');

This uses a regex to filter out all the whitespace, while keeping the list readable and rearrangeable. All the regex literal is doing is capturing the whitespace and then the replace method replaces the captured text with '' (the g on the end just tells the regex not to stop at the first match it finds, in this case, the first newline char.)

or, most nastily, you could just put the comments directly in your template literal, and then strip them with a regex:

const fields = `
    id, // post ID
    message, // post/status message
    created_time, // ...
    permalink_uri,
    type
`.replace(/\s+\/\/.*\*\/\n/g,'').replace(/\s/g,'');

That first regex will find and replace with an empty string ('') all instances of: one or more whitespace characters that precede a double slash (each slash is escaped by a backslash) followed by whitespace and the new line character. If you wanted to use /* multiline */ comments, this regex becomes a little more complex, you'll have to add another .replace() on the end:

.replace(/\/\*.*\*\//g,'')

That regex can only go after you strip the \n newlines out, or the regex won't match the now-not-multiline comment. That would look something like this:

const fields = `
    id, // post ID
    message, /* post/
                status message */
    created_time, // ...
    permalink_uri,
    type
`.replace(/\s+\/\/.*\n/g,'').replace(/\s/g,'').replace(/\/\*.*\*\//g,'');

All of the above will result in this string:

"id,message,created_time,permalink_uri,type"

There's probably a way to do that with only one regex, but it's beyond the scope here, really. And besides, I'd encourage you to fall in love with regexes by playing with them yourself!

I'll try to get a https://jsperf.com/ up on this later. I'm super curious now!




回答4:


Just don't use template strings:

const fields = [
    'id',  // comment blah blah
    'message',
    'created_time',
    'permalink_url',
    'type'
].join(',');

You pay the cost of the array and method call on initialization (assuming the JIT isn't smart enough to optimize it away entirely.

As pointed out by ssube, the resulting string will not retain the linebreaks or whitespace. It depends on how important that is, you can manually add ' ' and '\n' if necessary or decide you don't really need inline comments that badly.

UPDATE

Note that storing programmatic data in strings is generally held to be a bad idea: store them as named vars or object properties instead. Since your comment reflects your just converting a bunch of stuff into a url query string:

const makeQueryString = (url, data) => {
  return url + '?' + Object.keys(data)
    .map(k => `${k}=${encodeURIComponent(data[k))})
    .join('&');
};

let qs = makeQueryString(url, {
  id: 3,
  message: 'blah blah',
  // etc.
});

Now you have stuff that is easier to change, understand, reuse, and more transparent to code analysis tools (like those in your IDE of choice).



来源:https://stackoverflow.com/questions/40046764/is-it-possible-to-have-a-comment-inside-a-es6-template-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!