Search code examples
javascriptgetter-setter

Why do getters work differently in this two examples?


Why when we have this

function Car() {
  const fuel = 50
  return {
    fuel,
  }
}

const car = Car()
console.log(car.fuel) // 50
car.fuel = 3000
console.log(car.fuel) // 3000

And if we add a getter, the fuel property cannot be muted:

function Car() {
  const fuel = 50
  return {
    get fuel() {
      return fuel
    },
  }
}

const car = Car()
car.fuel = 3000
console.log(car.fuel) // 50

But then, if I try it on an isolated object it doesn't work the same way:

const person = {
  _firstName: 'John',
  _lastName: 'Doe',
  get fname() {
    return this._firstName;
  }
}
 
console.log(person.fname); // prints 'John'
person._firstName = 'Juan';
console.log(person.fname); //prints 'Juan'

Context: I was trying to figure out why setters exist, I couldn't wrap around the idea of it usefulness. I get why setters have a place. So I found this code snippet explaining that one of the advantages was to keep properties safe from changes. Reference here.


Solution

  • When you're doing

    function Car() {
      const fuel = 50
      return {
        fuel,
      }
    }
    
    const car = Car()
    

    Car() is just returning { fuel: 50 }, a plain object.

    So when you set car.fuel = 3000, it just changes to { fuel: 3000 }.

    Let's take a look at the second case.

    function Car() {
      const fuel = 50
      return {
        get fuel() {
          return fuel
        },
      }
    }
    
    const car = Car()
    

    Let me rename fuel and fuel() for clarity:

    function Car() {
      const a = 50
      return {
        get b() {
          return a
        },
      }
    }
    
    const car = Car()
    

    Here, when you do car = Car(), you can understand it as car = { get b(): {return a} }. When you define a getter function like this, you cannot change it.

    So when you do car.b = 3000, JS is saying "Oh, you're trying to change the value of b, but that is a getter function, you're not allowed to change it." JS being JS, it doesn't throw you an error though.

    const person = {
      _firstName: 'John',
      _lastName: 'Doe',
      get fname() {
        return this._firstName;
      }
    }
     
    console.log(person.fname); // prints 'John'
    person._firstName = 'Juan';
    console.log(person.fname); //prints 'Juan'
    

    This one is pretty self evident, person._firstName is just plain old any other property in an object, so you can change it however you want. But, similarly to the second case, if you try this:

    const person = {
      _firstName: 'John',
      _lastName: 'Doe',
      get fname() {
        return this._firstName;
      }
    }
     
    console.log(person.fname); // prints 'John'
    person.fname = 'Juan';
    console.log(person.fname); //prints 'John'

    It will not change fname.