Search code examples
javascriptconstantslet

Using let hello = `My age is ${age}` but updating age is not updating the age in this command


I wanted to set the greeting so I wouldn't have to type it out in full anymore.

So I did:

let hello = `My name is ${name} and I am ${age} years old`

So to have me greet, I would just type:

console.log(hello);

However, later I updated the age

++age;

But when I did that, and I greeted myself again

console.log(hello);

The "age" that is inside of that "hello" didn't show as updated.

For example,

let age = 20;
let name = "John";
let hello = `My name is ${name} and I am ${age} years old`
console.log(hello);

...The output is: My name is John and I am 20 years old.

Then I updated the age

++age;
console.log(hello);

...But the output is still: My name is John and I am 20 years old.

. .

Originally I had

const hello = `My name is ${name} and I am ${age} years old`

But changing "const" to "let" didn't seem to make a difference.

I also tried

age++;

instead of

++age;

to see if I was remembering that command incorrectly but neither seem to make a difference.


Solution

  • Once your hello assignment ran, hello has the static value of e.g. My name is John and I am 20 years old. Changing age won't have any effect on hello, unless you do the assingment again:

    let age = 20
    let name = "John"
    let hello = `My name is ${name} and I am ${age} years old`
    console.log(hello)
    
    age++
    hello = `My name is ${name} and I am ${age} years old` // << THIS
    console.log(hello)

    However, this is of course duplicate code which is never a good thing. So, you could use a function instead:

    const getHello = (age, name) => `My name is ${name} and I am ${age} years old`
    
    let age = 20
    let name = "John"
    console.log(getHello(age, name))
    
    age++
    console.log(getHello(age, name))

    Here, the variables are given as arguments. If you need it only in one place and you want to directly read from the local variables, you can also close over them, like this:

    let age = 20
    let name = "John"
    
    const getHello = () => `My name is ${name} and I am ${age} years old`
    
    console.log(getHello())
    
    age++
    console.log(getHello())

    Yet another way would be to keep using hello as local variable, but have a function that updates it, so you still need to remember updating it but it takes away the duplicate code of the actual string interpolation:

    let age = 20
    let name = "John"
    let hello
    
    const updateHello = () => {
      hello = `My name is ${name} and I am ${age} years old`
    }
    
    updateHello()
    console.log(hello)
    
    age++
    updateHello()
    console.log(hello)

    A less explicit way that appears more like an automatically updating variable would be using a getter. You can't define a local variable as getter though, but you can do it inside a class for example (or an object in general):

    class Test {
      constructor (age, name) {
        this.age = age
        this.name = name
      }
    
      get hello () {
        return `My name is ${this.name} and I am ${this.age} years old`
      }
    }
    
    const test = new Test(20, "John")
    console.log(test.hello)
    
    test.age++
    console.log(test.hello)


    Side note: The frontend framework Svelte has reactive declarations which work more in the way that you imagined here, using the $: prefix.

    <script>
      let name = "John"
      let age = 20
      $: hello = `My name is ${name} and I am ${age} years old`
    
      function handleClick() {
        age += 1
      }
    </script>
    
    <input type="text" bind:value={name}><br>
    <input type="number" bind:value={age}>
    
    <button on:click={handleClick}>
      Increase age
    </button>
    
    <p>{hello}</p>
    

    See live example