I am building up a constants.js file with URLs used in my ReactJS project. These strings include query parameters that can be used with the URL. However, the values used in these strings are only available in a component where the string is used, not in the constants file itself. So for example, I want something like this:
export const BASE_URL = 'https://example.com';
export const FOO_QUERY = '?foo=%s';
where %s is just a placeholder that can be replaced later in a component. (I borrowed printf() syntax from C here for illustration purposes.) What is the correct syntax to do something like this in JavaScript? Is it even possible?
I'd probably use a template literal in a function: The component calls the function with the foo value:
export const fooQuery = foo => `?foo=${foo}`;
Usage:
const query = fooQuery("foo value");
With tagged template literals you could do:
function query(parts, ...pos) {
return apply(...args) {
return parts.map((part, i) => part + args[ pos[i] ]).join("");
}
}
Usable as:
const find = query`?name=${0}&fullname=${0}&age=${1}`;
console.log(find("jonas", 18));
let string = 'bar';
console.log("Foo %s", string);
var teststr = (string) => `Foo ${string}`; //result: Foo bar
This question already has answers here:
Backticks (`…`) calling a function in JavaScript
(3 answers)
Closed 4 years ago.
Just asking to understand how it works:
function say(something) {
return something;
}
let name = `Reza`;
console.log(say `My name is`, name, '!');
It returns a very weird output. I think that My name is is a string within an array and everything else is just a string (correct me if I am wrong).
My Question is, what is the point of that and when would it make sense to use a function like that?
Also I would be glad if someone could tell me why My name is ${name} is not working (name returns as an empty string).
PS: I know that could use the function with parentheses and it would work but that's not my question.
why My name is ${name} is not working (name returns as an empty
string).
This is because you have to pull out the value of My name is from the array of string values and return it
Try this:
function say(something) {
var str0 = something[0]
return str0;
}
let name = `Reza`;
console.log(say`My name is${name}`, name, '!'); // My name is Reza !
We will receive thing like this:
I would like to point out that the ${name} does not mean anything at all, because inside the tag function, we didn't do anything with it.
This is the result after running your codes on the Chrome devtools:
Let's see how we can explain what is actually going on. Well then, what you're using is called Tagged templates:
A more advanced form of template literals are tagged templates. Tags allow you to parse template literals with a function. The first argument of a tag function contains an array of string values.
That's why we see an array in the result:
For instance, if we run this codes on Chrome devtools:
function say(something) {
return something;
}
console.log(say`anything`);
On the console tab, we will receive this result:
For more information, you could read it here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_templates
As we can see, the weird raw property, according to MDN - Raw strings, it is:
The special raw property, available on the first function argument of tagged templates, allows you to access the raw strings as they were entered, without processing escape sequences.
For example:
function tag(strings) {
console.log(strings.raw[0]);
}
tag`string text line 1 \n string text line 2`;
// logs "string text line 1 \n string text line 2" ,
// including the two characters '\' and 'n'
And you are using the console.log() method, according to MDN-Console.log() we have its signature:
Syntax: Console.log()
console.log(obj1 [, obj2, ..., objN]);
console.log(msg [, subst1, ..., substN]);
Parameters
obj1 ... objN
A list of JavaScript objects to output. The string representations of
each of these objects are appended together in the order listed and
output.
msg
A JavaScript string containing zero or more substitution strings.
subst1 ... substN
JavaScript objects with which to replace substitution strings within
msg. This gives you additional control over the format of the output.
In your case, you're passing multiple arguments into the Console.log() method, hence it will work as the document said here: Outputting multiple objects
Doing My name is ${name} should work. Its because your passing My name is to the say function as a tagged template literal, which by default passes the arguments as an array
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
say tag is missing the arguments to the placeholders in the template string:
function shout(parts, name/*<--HERE*/) {
return `${parts[0]}${name}${parts[1]}!!!`;
}
let name = `Reza`;
console.log(shout `My name is ${name}`);
say receives data from the template string as a split string around the placeholders:
[
"My name is ",
"!"
] Reza
Look at this example from the MDN Documentation:
function myTag(strings, personExp, ageExp) {
var str0 = strings[0]; // "That "
var str1 = strings[1]; // " is a "
var ageStr;
if (ageExp > 99){
ageStr = 'centenarian';
} else {
ageStr = 'youngster';
}
// We can even return a string built using a template literal
return `${str0}${personExp}${str1}${ageStr}`;
}
var person = 'Mike';
var age = 28;
var output = myTag`That ${ person } is a ${ age }`;
Your tagged template has a missing argument, it should include a strings array argument as first argument.
function say(strings, something) {
return strings[0] + "Mr. " + something +"!";
}
let name = `Reza`;
console.log(say `My name is ${name}`);
Make it simple
console.log `Hi there`;
why My name is ${name} is not working (name returns as an empty string).
console.log(say `My name is`, name, '!'); /* I don't see `${name}` here */
Also, name was never passed as an argument to say function!
function say(something) {
return something;
}
let name = `Reza`;
/* say without () */
console.log(say `My name is ${name} !`);
/* say with () */
console.log(say(`My name is ${name} !`));
let who = 'everyone';
console.log `Hello ${who}`; /* note, no -> () */
console.log(`Hello ${who}`);
I've spent hours researching documents in order to answer your question. And I'll try my best to explain it simply.
My first answer is, in fact, a text explanation. However, I remember W3Schools once said that:
Examples are better than 1000 words. Examples are often easier to
understand than text explanations.
Well then, this answer supplements all explanations with clarifying "Try it Yourself" examples.
There are two concepts in Javascript that involved: the Tagged templates and the Console.log() method.
I'll re-write your codes, breaking them into two parts, like this: (the executed result remains the same).
// part 1
function say(something) {
return something;
}
let name = `Reza`;
let output = say`My name is`;
// part 2
console.log(output, name, '!');
Let's see how these two parts related to the concepts of Tagged templates and the Console.log() method, respectively.
First, examine this example:
Example 1:
function say(something) {
return something;
}
let output = say`My name is`;
console.log(output)
After running this example, we'll see an array that contains one element which is a string: "My name is"
This is the behavior of the Tagged templates
Before we actually dive into how Tagged templates works, let's take a look at some examples below:
Example 2:
function say(something) {
return something[0];
}
let output = say`My name is`;
console.log(output)
After running the example 2, we'll receive a string: "My name is", instead of an array as the example 1 did.
Well then, what if I want to pass a name to it? see this:
Example 3
function say(something, name) {
return `${something[0]}${name}`;
}
let name = 'Reza';
let output = say`My name is ${name}`;
console.log(output)
Yay! It works as expected. Well then, what if I want to pass two arguments instead of one? see this:
Example 4
function say(something, name, age) {
let str0 = something[0];
let str1 = something[1];
let str2 = something[2];
return `${str0}${name}${str1}${age}${str2}`;
}
let name = 'Reza';
let age = 1000;
let output = say`My name is ${name}, I'm ${age} years old!`;
console.log(output)
Quite clear, right? This is how we use Tagged templates.
The examination of the Tagged templates is done now. Let's see how Console.log() method works.
Example 5
console.log(`My name is `)
We are all familiar with this usage of Console.log() method, passing one argument. Well then, what if I want to pass multiple arguments to it. See this:
Example 6
let name = `Reza`;
console.log(`My name is `, name, '!')
It combined all together into one single output.
Well then, for now, let's go back to your sample:
function say(something) {
return something; // the `something` is still an array
}
let name = `Reza`;
console.log(say `My name is`, name, '!');
// the console.log() method will try to combine all these three arguments
// into one single output
// this is why we got the output as an array with a string: "name" and a string: "!"
We could fix it like this:
Example 7
function say(something) {
return something[0];
}
let name = `Reza`;
console.log(say`My name is`, name, '!');
Or like this:
Example 8
function say(something, name) {
return `${something[0]}${name}`;
}
let name = `Reza`;
console.log(say`My name is ${name} `, '!');
However, let's see this example:
Example 9
function say(something, name) {
return `${something[0]}${name}`;
}
let name = `Reza`;
console.log(say`My name is ${name} `, name, '!');
We'll receive My name is Reza Reza !. I believe that, for now, we all understand why we got it.
I'd like to do something like this:
let template = `The first value is ${v1} and the second value is ${v2}`;
template.interpolate(v1,v2);
Is this possible in Javascript / Typescript? The documentation I've found contains the variables being interpolated into the template within the same context that the template string is created in.
As indicated in the comments there are a lot of ways to do this in Javascript, but I'm specifically wondering whether we can create predefined templates with backticks? For example the duplicate link uses quotes, which do not support multiline template markup.
According to the MDN template literals reference you can create your own templates using backticks, please refer to the Tagged Templates section.
Adapting to your example:
function template(strings, ...keys) {
return function(...values) {
var dict = values[values.length - 1] || {};
var result = [strings[0]];
keys.forEach(function(key, i) {
var value = Number.isInteger(key) ? values[key] : dict[key];
result.push(value, strings[i + 1]);
});
return result.join('');
};
}
var interpolate = template`The first value is ${'v1'} and
the second value is ${'v2'}`;
interpolate({ v1: 1, v2: 2 });
Whose output should be:
The first value is 1 and
the second value is 2
Hope it helps
Thanks #RodrigoFerreira. I read up on the template literals section and your answer and realized that it's as simple as defining a function and passing that around instead of using a direct template literal:
const f = (v1:any)=> {
return `v1 is ${v1}`;
}
console.log(f("Howdy Rodrigo!")); //logs v1 is Howdy Rodrigo!
I wish to create a function that takes an argument as a template literal, however will throw an error if the template literal has any variables within the template.
For example the following is valid.
const value = checker(`hello world`)
However this would throw an error.
const value = checker(`hello ${name}`)
What's the best way to achieve this?
Template literals allow for tagging, it can be achieved like this:
var a = 5;
var b = 10;
function noVarTemplate(strings, ...values) {
if (values.length) throw new Error('the noVarTemplate does not allow template literal values')
return strings[0]
}
const value = noVarTemplate`Hello World`
// const value = noVarTemplate`Hello ${a}`
console.log(value)
I read that in JS stings are immutable, and even though the default for JS appears to be "pass by reference", passing the same string around a recursive hierarchy will not append to the same string but rather create copies.
My scenario requires for a single string object to be created once, and passed around in a very deep and long hierarchy of recursive and other functions, so how can I achieve this? I am a C++ guy, and in C++ it is quite easy... just pass by reference and all functions work on the same bit of string.
You can simulate pass by reference for primitive values using a wrapper object. This involves altering your functions to be aware of that:
function append(strWrapper,n) {
if (n <= 0) {
return strWrapper;
} else {
strWrapper.val += n;
return append(strWrapper, n-1);
}
}
console.log(append({ val : '' }, 9).val); // 987654321
Of course the wrapper object could turn into a wrapper class if you are so inclined.
*JS does pass by reference only for objects, not for primitive values
You can pass Array/String Objects as they are passed by reference , something like below code to find subsequences i have passed array of string (output) to store all subsequences in which is passed in every call
`
function subsequence( input, output){
if(input.length==0)
{
output[0]="";
return 1;
}
let smallStr = input.substr(1);
let smallerSeqSize = subsequence(smallStr,output);
for(let i=0;i<smallerSeqSize;i++){
output[smallerSeqSize+i] = input[0]+output[i];
}
return 2*smallerSeqSize;
}
function main(){
let input = "abc";
let output = new Array("")
let sizeOutput = subsequence(input,output);
console.log(output)
}`