I wrote this for a CodeWars challenge while trying to learn ECMAScript and would really like to have some advice on how it could be improved. What I don't like about this code myself, but am unsure on how to improve: - I didn't yet found a way to have a class in ECMAScript that mixes public and private methods in a way, where the public methods (and only them) can still access private methods and vars. - (Partly caused by the point above) I think the code is way too verbose and bloated. Too much of it is wasted on language specific implementation details. There must be a smarter way to do this - I feel like I could write the same functionality in PHP using 10% of the lines I needed now. <!--- ---> function LRUCache(capacity, init) { this._capacity = capacity; this._size = 0; this._accessMap = []; this._items = []; this._frozenMethods = ['cache', 'delete']; this._functionalProps = ['size', 'capacity']; this.cache = function(key, value) { if( this._accessMap.indexOf(key) == -1 ) { this._addNewItem(key); } this._items[key] = this[key] = value; this._updateAccessMap(key); return this; }, this.delete = function(key) { if(this._frozenMethods.indexOf(key) !== -1 || this._functionalProps.indexOf(key) !== -1) { return false; } if( this._accessMap.indexOf(key) === -1 ) { return true; } delete this[key]; delete this._items[key]; this._size--; this._updateAccessMap(key, true); return true; }, this._removeOldest = function() { var key = this._accessMap[0]; this.delete(key); }, this._updateAccessMap = function(key, remove) { index = this._accessMap.indexOf(key); if( index !== -1) { this._accessMap.splice(index, 1); } if(!remove) { this._accessMap.push(key); } }, this._addNewItem = function(key) { this._size++; if(this._size > this._capacity) { this._removeOldest(); } Object.defineProperty(this, key, { get: function() { this._updateAccessMap(key); return this._items[key]; }, set: function(v) { this._items[key] = v; this._updateAccessMap(key); return this; }, enumerable: true, configurable: true }); }; var obj = this; this._frozenMethods.map( function(v) { Object.defineProperty(obj, v, { enumerable: false, writable: false, configurable: false }); }); ['_items', '_capacity', '_accessMap', '_frozenMethods','_size', '_functionalProps', '_removeOldest','_updateAccessMap','_addNewItem'].map( function(v) { Object.defineProperty(obj, v, { enumerable: false, configurable: true }); }); Object.defineProperty(this, 'capacity', { set: function(v) { while(this.size > v) { this._removeOldest(); } this._capacity = v; }, get: function() { return this._capacity; }, configurable: false }); Object.defineProperty(this, 'size', { set: function(v) { return false; }, get: function() { return this._size; }, configurable: false }); if(init) { for(var attr in init) { if( !init.hasOwnProperty(attr) ) { continue; } this.cache(attr, init[attr]); } } }