Eliran Pe'er
Eliran Pe'er

Reputation: 2639

String.raw with a string only works without parenthesis

I know you can use template literals to supply the first parameter of a method, for instance:

const f = x => "hello ," + x;
f`world` // returns 'hello, world'

So I can somehow understand why this code works:

String.raw`bla bla`

However, I can't seem to understand why the same method call with parenthesis throws an error:

String.raw(`bla bla`)

throws: Uncaught TypeError: Cannot convert undefined or null to object

My questions are:

Upvotes: 3

Views: 1277

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1075109

... I can't seem to understand why the same method call with parenthesis throws an error

It's not the same method call.

This:

String.raw`bla blah`

...calls raw passing in the template.

But this:

String.raw(`bla blah`)

...processes the template, creating a string, and then calls raw with that string. Exactly as though you'd written:

const str = `bla blah`;
String.raw(str);

...but without the constant.

That's not the same thing at all.

Why exactly the first snippet works?

Because that's how tagged template literals work. They're their own thing.

Why String.raw only works when it's being called this way?

Because it's designed to be run as a tag function, but you're calling it like a non-tag function and not passing it the information a tag function receives when called as a tag function.

It might help if you see what a tag function receives:

function foo(strings, ...tokenValues) {
    console.log("strings: ", JSON.stringify(strings));
    console.log("strings.raw: ", JSON.stringify(strings.raw));
    console.log("Token values (" + tokenValues.length + "):");
    tokenValues.forEach((val, index) => {
      console.log(`${index}: ${typeof val}: ${JSON.stringify(val)}`);
    });
}
const token = "tokenValue";
const obj = {
   foo: "bar",
   num: Math.random()
};
foo`bla \nbla ${token} bla ${obj} done`;

Note how the function receives an array with the non-token parts of the template (the "strings"), followed by arguments with the values of each token. Also note that those values are the actual values, not strings of the values.

More about template literals and tag functions:

Upvotes: 6

simbathesailor
simbathesailor

Reputation: 3687

Or if you want to call String.raw as a function you need to call it like this

String.raw({raw: `xyx`})

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

Two ways of calling String.raw

String.raw(callSite, ...substitutions)

String.raw`templateString`

Upvotes: 2

Related Questions