问题描述:

Consider the following code:

function f() {

console.log(Array.from(arguments));

}

var x = 2;

var y = 3;

f`before ${x} ${y} after`;

The arguments for f would be (according to Traceur):

["before ", " ", " after"], 2, 3

Let's say I want to concatenate all literal strings with substitution values.

How do I do that in the correct order?

Do I need to match 'split points' in the first array with each argument after first?

网友答案:

According to the wiki for the Draft ECMAScript 6 Specification, it is more complicated because templates take escape sequences into account:

The template

quasiTag`literalPortion\0 $x literalPortion1`

will desugar to

// Declaration hoisted to top of module.
// Escape sequences in the hoisted declaration are not decoded according to CV(EscapeSequence).
// The calls to Object.freeze use the original definition of that method.
const unguessableCallSiteId1234 = Object.freeze({
  raw: Object.freeze(["literalPortion\\0 ", "literalPortion1"]),
  cooked: Object.freeze(["literalPortion\u0000 ", "literalPortion1"])
});

...

  // In-situ
  // Escape sequences in the arguments are decoded.
  // unguessableCallSiteId1234 is ideal as a key into a weak map used to memoize
  // extraction of meta-data, custom escaping conventions, and other state
  // that can be derived from the literal portions, so does not vary from
  // call to call from the same call-site.
  quasiTag(unguessableCallSiteId1234, x)

EcmaScript Quasi-Literals - Desugaring

So arguments should contain the substitution values as you see with traceur but the literal portions are an object and not an array.

If you want to implement it for code compiled with traceur you could do something like in the following unoptimized example.

let concatenated = "";
Array.forEach(args[0], (e, i) =>
    concatenated += e + ( i < arguments.length - 1 ? arguments[i+1] : "")
);

For real ECMAScript 6 code take a look at the Default Quasi Tag implementation, as bergi suggested in the comments.

网友答案:

There's always one more literal portion than substitution. The first literal is the first part of the template (or empty string if it starts with a substitution), and the last literal is the tail of the template string (or, again, an empty string if it ends with a substitution).

To get the parts in order, access literal[0], sub[0], literal[1], ..., sub[sub.length-1], literal[sub.length].

Here's a simple starting point:

function simpleTag(lit, ...sub) {
  return sub.reduce(
    // Add next substition and following literal
    (soFar, s, i) => soFar + s + lit[i+1],
    lit[0] // Start with the first literal
  );
}
相关阅读:
Top