16

I'd like to create a class in JS that uses native getters and setters. I know I can create getters/setters for objects, like so:

var obj = {
    get value(){
        return this._value;
    },
    set value(val){
        this._value = val;
    }
}

I also know that I can use this.__defineGetter__ inside a class/function, but MDN says that using __defineGetter__() etc is discauraged.

Is there any better way to add getters and setters to js class than:

function class(){
};

class.prototype = {
   get value(){
        //....

}

?

Kuba Orlik
  • 3,360
  • 6
  • 34
  • 49
  • 4
    exact duplicate of [How to define setter/getter on prototype](http://stackoverflow.com/questions/10592753/how-to-define-setter-getter-on-prototype) – Bergi Feb 04 '14 at 22:31
  • 1
    Yes there is look at [Object.defineProperty()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) – Givi Feb 04 '14 at 22:45

3 Answers3

18

2019: Hooray for ES6!

class Person {
    
    get name() {
        return this._name + '!!!'
    }

    set name(newValue) {
        this._name = newValue
    }

    constructor(name) {
        this._name = name
    }
}

const me = new Person('Zach')
console.log(me.name)            // Zach!!!

me.name = 'Jacob'
console.log(me.name)            // Jacob!!!

// Of course, _name is not actually private.
console.log(me._name)           // Jacob
user1160006
  • 533
  • 4
  • 12
  • 2
    In case you're looking for truly private fields, take a look [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Class_fields). Private class field is still in TC39 stage 3 as of 2020-04-30, but has nonetheless already gained support on quite a few platforms, **notably NodeJS since v 12.0**. – cyqsimon Apr 30 '20 at 03:33
  • Private classes have been supported since early 2021 in most browsers. Just use `#name` instead of `_name`. See here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields – ArtOfWarfare Nov 23 '22 at 22:41
11

The cleanest way to define properties on a class is via Object.defineProperties. This allows you to define all of your properties in a single, easily readable block. Here's an example:

var MyClass = function() {
    this._a = undefined;
    this._b = undefined;
};

Object.defineProperties(MyClass.prototype, {
    //Create a read-only property
    a : {
        get : function() {
            return this._a;
        }
    },
    //Create a simple read-write property
    b : {
        get : function() {
            return this._b;
        },
        set : function(value) {
            this._b = value;
        }
    }
});

There are a plethora of other options when defining properties, so be sure to check out the link I posted for more information. It's also important to keep in mind that even the most basic getter/setter property is only as fast as a method call in current browsers, so they can become a bottleneck in performance-intensive situation.

Matthew Amato
  • 1,992
  • 17
  • 21
-2

How about this implementation:

function makeObject(obj, name) {
    // The property
    var value;

    // The setter
    obj["get" + name] = function() {return value;};

    // The getter
    obj["set" + name] = function(v) {
        value = v;
    };
}

To experiment:

var obj = {};
makeObject(obj, "Name");
obj.setName("Lolo");
print(obj.getName());

Of course, you can test name for validity before storing it in value. The test can be supplied as an additional argument to the makeObject function.

user2845946
  • 1,755
  • 29
  • 38
  • Yes, that is one way to define getters and setters, but what's great about 'get' and 'set' syntax is that the functions get triggered on regular assignment, that is on 'obj.value=2' the setter function is being called – Kuba Orlik Feb 05 '14 at 06:12
  • 1
    These are not "native getters and setter" as were asked for. – Uniphonic Nov 09 '17 at 18:35
  • @user2845946 Looks like you replied to me and then deleted the comment? You said you just down voted me "at random". Retaliatory serial down voting action like that is not just mean, that's a disservice to the community as a whole. If you can put a disclaimer in your answer that it is not an alternative way to create native getters and setters, then I'll undo my down vote. Otherwise, I think the answer is misleading, as people may think it's an alternative synax for creating native getters and setter, but it's not. If you're presenting a workaround, then please state it as such. – Uniphonic Nov 10 '17 at 16:45