user7293516
user7293516

Reputation:

How to define getters and setters in new ECMAScript 2015 JavaScript classes

I'm trying do define a simple class called Mail using the new ECMAScript 2015 JavaScript classes as defined here.

I came up with this constructor and tried the following getter:

class Mail {
   constructor(sender, date, subject, text) {
        this.sender = sender;
        this.date = date;
        this.subject = subject;
        this.text = text;
   }
   get sender() {
       return this.sender;
   }
}

But when I tried to use that method, it didn't work.

var mail = new Mail("@mail.com", Date.now(), "Testing", "Text");
console.log(mail.sender());

Returned:

TypeError: mail.sender is not a function

So, my doubt is:

  1. Is it necessary to define getters and setters like in Java or can I simply access field like mail.sender (or so)?
  2. If it is necessary, how to properly define getters and setters to each of class instance variables?

Upvotes: 1

Views: 1290

Answers (4)

Thomas
Thomas

Reputation: 12657

getter and setter are basically hooks to capture get- and set- actions for properties of an object. They are functions, but they seem (to the code that uses this Object) like a property.

var mail = new Mail("@mail.com", Date.now(), "Testing", "Text");
console.log(mail.sender); //no brackets

and if you add a setter, main.sender = "@foo.bar".

And I'm wondering that your code didn't get stuck in an infinite recursion, since your getter called itself.

class Mail {
   constructor(sender, date, subject, text) {
        this._sender = sender;
        this._date = date;
        this._subject = subject;
        this._text = text;
   }

   //this IS `this.sender`!
   //it should not `return this.sender`, since this would call this getter again, 
   //and you get stuck in an infinite recursion.
   get sender() {
       return this._sender;
   }

   //and a possible setter, that handles 
   //instance.sender = whatever;
   set sender(value) {
       this._sender = value;
   }
}

Edit:

Does this mean that I can just ignore get and set methods because I can directly access object field?

you don't need getter or setter to make any property public in JS, simply defineing this property makes it public available. JS works the other way around, you have to take additional efforts to make things private (see closures). In JS everything is by default public.

But you can use getter (and setter) to fulfil additional tasks, like:

class Person{
    constructor(firstName, lastName){
        //regular public properties
        this.firstName = firstName;
        this.lastName = lastName;
    }

    //a composed value, that you can access like a property
    get fullName(){
        return this.firstName + " " + this.lastName;
    }

    //you could also add a setter like this
    set fullName(value){
        [this.firstName, this.lastName] = value.split(/\s+/g);
    }
}

var john = new Person("John", "Doe");
console.log(john.fullName);

Upvotes: 4

user2345
user2345

Reputation: 3227

To use getters and setters, you just need to use and set the property. in your case: mail.sender. This will call the getter if you are using the value, or the setter if you are overriding the current value.

class Mail {
    constructor(sender) {
        this._sender = sender;
    }

    get sender() {
        return "Sender: " + this._sender;
    }

    set sender(val) {
        this._sender = val.toLowerCase();
    }
}

const m = new Mail("TEST");
console.log(m.sender); // => "Sender: TEST"

m.sender = "TEST";
console.log(m.sender); // => "Sender: test"

Note that I used _sender to store the value to prevent a Maximum call stack size exceeded error.

You can use the property like any other property, and it will automatically call the getter or setter.


If what you were looking for is encapsulation, you could design your classes like so:

const Mail = (function() {
    let sender; // this is "private"

    return {
        title: "public", // This is public
        get sender() {
            return sender;
        },
        // ...
    };
});

In this case, you would then create new Mail objects like so:

const mail = Mail();

You could return a function in the Mail function in order to be able to instantiate new objects with the new keyword.

Upvotes: 0

NonPolynomial
NonPolynomial

Reputation: 329

JavaScript has no concept of classes. The class keyword is just syntactic sugar.

What a class do is, it generates a constructor function for you.

const Person = class { // or `class Person`
    constructor(name) {
        this.name = name;
    }

    say(msg) {
        return `${this.name} says: "${msg}".`;
    }
}

That's exactly the same, what you will achieve with the following code.

const Person = function(name) {
    this.name = name;
};

Person.prototype = {
    say(msg) {
        return `${this.name} says: "${msg}".`;
    }
};

If you need private variables, you have to work with closures.

const Person = class { // or `class Person`
    constructor(name) {
        this.getName = () => name;
        this.setName = (newName) => {
            name = newName;
        }
    }

    say(msg) {
        return `${this.getName()} says: "${msg}".`;
    }
}

let p = new Person('me');
console.log(p.name); // undefined
console.log(p.getName()); // 'me'
p.setName('he');
console.log(p.getName()); // 'he'
console.log(p.say('something')); // 'he says: "something".'

I advice you to not use class and to avoid new. If you need an object, you simply can use factory functions:

const Person = function(name) {
    let person = Object.create(Person.prototype);
    person.name = name;
    return person;
};

Person.prototype = {
    say(msg) {
        return `${this.name} says: "${msg}".`;
    }
};

Upvotes: 0

jonlink
jonlink

Reputation: 531

You actually did more than you need to. You don't need getters as you specified.

Try this:

class Mail {
 constructor(sender, date, subject, text) {
    this.sender = sender;
    this.date = date;
    this.subject = subject;
    this.text = text;
  }
}

var mail = new Mail("@mail.com", Date.now(), "Testing", "Text");
console.log(mail.sender);

Upvotes: 0

Related Questions