Paweł
Paweł

Reputation: 4516

How to define a public property in the javascript class?

With ES5 constructor and prototype approach I can add public (prototype) properties as below:

function Utils(){}
Utils.prototype.data = {};

var utils = new Utils();
console.log(utils.data);  //{}

The ES6 class allows me to define only public methods in the class. I build an app with a class-approach and I don't want to mix constructors and classes features. The working code that I figured out is:

class Utils(){
  get _data(){
    const proto = Object.getPrototypeOf(this);
    if(!proto._status) proto._data = {};
    return proto._data;
  }
}

const utils = new Utils();
console.log(utils._data); //{}

When I call _data getter method, it checkes whether the _data property exists in the prototype object. If so, it returns it, otherwise it initiates the _data property.

Is it a good practice? Is there any other way to do it better?

Upvotes: 1

Views: 11217

Answers (2)

yqlim
yqlim

Reputation: 7080

I don't know if the code you provided is your full code or not, but when I run it, it throws an error:

class Utils {
  get _data(){
    const proto = Object.getPrototypeOf(this);
    if(!proto._status) proto._data = {};
    return proto._data;
  }
}


/* TEST */
const a = new Utils();
a._data.ok = 'ok';

const b = new Utils();
console.log(b._data.ok);

If I understand you correctly, you want all instances of Utils to share the same data property.

There is a few ways that I can think of to do what you need, but it might "mix constructors and classes features" (I don't really get what you mean by that).

1: Good ol' ES5 way

class Utils {}
Utils.prototype.data = {};

/* TEST */
const a = new Utils();
a.data.ok = 'ok';

const b = new Utils();
console.log(b.data.ok);

2: Same as your way, but in it's constructor

class Utils {
  constructor(){
    if (!this.data) {
      Utils.prototype.data = {};
    }
  }
}

/* TEST */
const a = new Utils();
a.data.ok = 'ok';

const b = new Utils();
console.log(b.data.ok);

Though, as the data property needs to be shared across instances, I'd suggest you to add the property to its prototype using Object.defineProperty method to make it unwritable and unconfigurable:

Object.defineProperty(Utils.prototype, 'data', {
    value: {},
    writable: false,
    enumerable: true,
    configurable: false
});

This is to ensure the data property cannot be reassigned or deleted, thus minimising the chance of mistakenly reset the data or etc.

I'd recommend the first way (with Object.defineProperty) because it is :

  1. More foolproof
  2. Clearer
  3. Easier to maintain

Upvotes: 1

Mitch Lillie
Mitch Lillie

Reputation: 2407

To make data a public instance property:

class Utils {
  constructor () {
    this.data = {}
  }
}

To make data a public static property, get/set is probably the best way:

let data = {}
class Utils {
  get _data () {
    return data
  }
  set _data (d) {
    data = d
  }
}

Upvotes: 2

Related Questions