34
class Employee {

    constructor(name, age) {
        this._name = name;
        this.age = age;
    }

    doWork() {
        return `${this._name} is working`;
    }

    get name() {
        return this._name.toUpperCase();
    }

    set name(newName){
        if(newName){ 
            this._name = newName;
        }
    }
}

let man = new Employee('A', 10);
console.log(man.name, man.age);
man.name = 'B';
man.age = 20;
console.log(man.name, man.age);

Here is my code. I created a getter and setter for _name member. I did not create a getter and setter for age.

But both can update these two fields like this man.name = 'B';man.age = 20;

So I am confused, are getter and setter necessary in JavaScript?

Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
BlackMamba
  • 10,054
  • 7
  • 44
  • 67
  • Yes, they are necessary sometimes. If you don't need them in your code, just don't use them. – Oriol Jan 15 '16 at 05:55
  • For perspective, this question is answered for Java in [this question](https://stackoverflow.com/questions/42342623/why-use-getters-and-setters-in-javascript). Some aspects are similar. – Dan Dascalescu Apr 07 '19 at 21:03

6 Answers6

58

Are getter and setter necessary in JavaScript?

Necessary is a bit of an undefined word. Any problem can be solved without a getter and setter (usually by changing the interface to methods instead of direct property access), just like any problem can be solved without a for loop (by substituting a while loop and manually maintained loop variables), but both are useful features to have in a programming language because when they are a match for a use case, then they are the cleaner and more convenient way to program. Thus, they are "useful" and "helpful".

A getter or setter can be very useful at times, but they only need to be used when their specific functionality is required - otherwise plain property access without a getter or setter can be just fine.

A getter has use when you want to run some code every time a property is requested. In your example, the getter always returns an uppercase version of the name regardless of what the case of the name is, while reserving the actual case for internal use.

A setter has use when you want to run some code every time a property is set. In your case, it prevents the setting of a falsey name. You can't implement either of those features without a getter/setter.

Direct property access is a perfectly fine way to do things when you don't need getter or setter special logic.

It's also possible that getters and setters may get and set some property that is not publicly available (so not available at all via a normal property access), either because it's stored somewhere differently (not as a property on this object) or stored privately or even that it's stored else such as in some hardware device. In these cases, the getter and setter simulate the value being in a property when it actually isn't. So, they simplify the interface while allowing the actual value to be stored or retrieved from anywhere.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • 1
    @tera_789 - Could "what" be done with basic functions? The OP could have created two regular methods called `getName()` and `setName()`, but that would have been a different interface than using setters and getters behind a property interface. If you have a virtual property that you want there to be property interface access to, you can only do that with setters and getters. Otherwise, you have method access for getting and setting and those can be done with normal methods. So, it depends upon the type of interface you want your object to have. – jfriend00 Sep 21 '18 at 05:24
  • @tera_789: your question is a good one and has been asked [here](https://stackoverflow.com/questions/42342623/why-use-getters-and-setters-in-javascript). – Dan Dascalescu Apr 07 '19 at 21:04
  • From an OOP standpoint this answer seems superficial. Generally, at least in OOP, it is a bad idea to manipulate fields directly. – EmilCataranciuc Apr 29 '20 at 09:53
  • Why is it fine for plain property access without a getter or setter. I come from a Java background so i'm trying to understand why this is okay. In Java it's always better to encapsulate with a getter and setter for polymorphism. If you have a public field in a class, there will not be any flexibility in hiding that property if you extend it correct? So shouldn't we use setters/getters even if you don't need it right now? – Plee May 19 '21 at 18:49
  • 1
    @Plee - So you're arguing that every single property of every single object should only be accessed via a getter and setter? Really? Why not make a given property accessed via a getter/setter only when there's a benefit/need? You can always add a getter/setter later (when there's an actual reason to have one) as it doesn't change the way the property is accessed at all. Meanwhile keeping things as plain properties that don't need a getter/setter retains performance optimizations of plain properties and keeps your code simpler which are both good things. – jfriend00 May 19 '21 at 19:35
  • 1
    @Plee - Plus, comparing Javascript to Java will not lead you in a good direction. They are different languages with different design tools, different things that affect performance, different goals, etc... When I first learned Javascript after coming from C++, I did all sorts of things in Javascript because of my C++ background that I ended up regretting. One needs to learn the new language for what it is and how to best write code in that language rather than trying to take design opinions from another language and assume they apply to Javascript. – jfriend00 May 19 '21 at 19:37
  • @jfriend00 - Appreciate the response. In Java yes it's encouraged to wrap every property with a getter and setter. My main concern is the "Open for extension, closed for modification" principle which is why i'm asking if javascript has some sort of functionality to uphold this. When you say add a getter/setter later, you mean changing the file? Or is there a way to add functionality later in subclasses? Maybe something similar to python's property decorator? – Plee May 19 '21 at 20:18
  • 1
    @Plee - I'm not sure what you're asking there. I think this is beyond the scope of what we can properly do in comments. If you want to pursue this further, I'd suggest you ask your own question that targets what you said in your last comment. You can drop a link to the question here in a comment and I'll take a look. – jfriend00 May 19 '21 at 22:51
10

Necessary? No.

Are there scenarios that would best be expressed as a getter/setter? Yes. Consider "Computed Properties":

//declare an object
rectangle = {
   x: 10,
   y: 20,
   get area() { return this.x * this.y }  //won't occupy storage
}

//usage
log('the area is', rectangle.area)        //=> 'the area is 200'.
                                          //   cleaner syntax (no parentheses)

Consider the needs of API designers - most likely they'll be hyper-sensitive about how users perceive their API. Every bit (or in this case, parentheses) counts towards cleaning up the interface.

jonathangersam
  • 1,137
  • 7
  • 14
6

Yes they are very necessary. Just not for every property.

Here are two reasons to have setters:

1. You need to validate the incoming value.

Let's say that you have a value that must be an integer between 0 and 100. Your setter can validate that the incoming value is of the correct type and within correct range:

class Range {
  set value(newVal) {
    let val = Number(newVal);
    
    if( newVal == null || typeof newVal === 'string' || !Number.isInteger(val) || val < 0 || val > 100 ) {
      const err = `'value' must be an integer from 0 to 100 and not ${newVal}`;
      console.error(err);
      //throw new TypeError(err);
    }
    
    // save newVal
  }
}

const x = new Range();
x.value = 200;
x.value = 10;
x.value = "10";
x.value = new Number(22);

2. You need to do something every time a value changes

class ValOutput {
  constructor(el) {
    this._el = el;
  }

  set value(newVal) {
    this._el.innerHTML = `The value is ${newVal}`;
  }
}

const output = document.getElementById('output');
const x = new ValOutput(output);
x.value = 100;
setTimeout(() => {
  x.value="after timeout";
}, 2000);
<div id="output"></div>

Here are two reasons to have a getter:

1. The value is computed

class Rect {
  constructor(l = 0,t = 0,r = 0,b = 0) {
    this.left = l;
    this.top = t;
    this.right = r;
    this.bottom = b;
  }
  
  get height() {
    return this.bottom - this.top;
  }

  get width() {
    return this.right - this.left;
  }
}

let a = new Rect(0, 10, 33, 55);
console.log(a.width, a.height);

 a = new Rect(35, 50, 200, 200);
console.log(a.width, a.height);

2. You are proxying a value from another object

class OtherThing {
  constructor(a) {
    this.a = a;
  }
}

class MyObj {
  constructor(oVal = 0) {
    this._otherThing = new OtherThing(oVal);
  }
  
  get a() {
    return this._otherThing.a;
  }
}

const x = new MyObj();
console.log(x.a);

const y = new MyObj('tacos');
console.log(y.a);

Hiding private variables

getters and setter are a great way to hide private data. Yes I know that the ES spec is introducing private variable but here is an example that works until that spec is standard.

const privateVars = new WeakMap();

class MyObj {
  constructor(inVal) {
    const pVars = {
      age: inVal,
      dog: ''
    }
    
    privateVars.set(this, pVars);
  }
  
  get dog() {
    return privateVars.get(this).dog;
  }
  set dog(newVal) {
    privateVars.get(this).dog = newVal;
  }
}

const x = new MyObj(10);
const y = new MyObj(20);


x.dog = "woof";
y.dog = "bark";

console.log(x.dog);
console.log(y.dog);

Do you need getter and setters? No. Are they necessary? Yes.

Intervalia
  • 10,248
  • 2
  • 30
  • 60
3

One of the main reason the getter and setter feature was implemented was to close a feature gap that required people to hack a js interpreter/browser to achieve one feature that browsers could do:

element.innerHTML = "<div> some HTML string </dif>";

Now, innerHTML may look like a property but it actually behaves more like a function. It's actually an HTML compiler.

You can see this by trying to do:

element.innerHTML += "<table>";
element.innerHTML += "<tr><td>test</td></tr>"; // does not work

This is because the first "call" to innerHTML compiles the html to:

<table></table>

The second line will fail because <tr> outside of a table is invalid HTML.

With getter and setter you can finally implement a feature like this in pure javascript - make property access trigger a function call.

Of course, innerHTML is just one example of getters and setters and a very bad example of an API at that. It's up to your creativity what you can actually do with getters and setters.

Now, for my personal opinion (and it's only my opinion so take it for what it's worth): I think innerHTML provides a good example for why getter and setters should not normally be used. The confusion over <table> is one good example of breaking user's expectation. If innerHTML was implemented as element.appendHTML() it's behavior would be less surprising. As a programmer I'd be very surprised if a property access does something I don't expect.

That said, I am glad that getters and setters exist to make language library features self-implementable without needing to resort to hacking in C/C++.

slebetman
  • 109,858
  • 19
  • 140
  • 171
-1

The reason why we use the class is that holds all properties of a single a entity.But you can get accomplished just by creating an object and can append properties to that when ever you need.

When the code grows bigger you cannot be able to debug where your code fails.If you follow the structure you can be easily able to dubug.Because every entity will be in separate file and logic will be separate.

But JavaScript is an object oriented programming language.the reason why we use classes instead of objects, that is the same for getters and setters.It's not like where you can use where you don't need.It's a good practice to set and get all properties via setters and getters.

After some point of time you may face adding some condition while setting a property, like if a persons age is greater than 100 you should not set in the property.At that point of time you need to change in your base class, and also in your child classes.That will be the hardest part of our life(code refactoring).So avoid these kind of problems and make your variables safe, from my point of view we should use getters and setters.sorry for the long answer

Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
sundar
  • 398
  • 2
  • 12
-2

Using getter and setter methods depends on your property in class, if you want make an property just to be read-only its true to use getter method as follow:

function Person(name, age){
  var _name = name;
  this.age = age;
  
  this.getName = function(){
    return _name;
  }
}

var teacher = new Person('Sara', 24);

//now you can just get the name of teacher 
alert(teacher.getName());
  
Heartbit
  • 1,698
  • 2
  • 14
  • 26
  • You can do it just by adding a new method like `setName` so this is just a way to immutate the `_name` and just for `es3` style code. – Heartbit May 13 '18 at 12:44