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.
JavaScript ain't classical OOP. Don't force it to be like one. The default inheritance pattern in JS is prototypal, and everything is public. You could define the methods inside the constructor to get the "public accessing private" (like you just did). But that defeats the purpose of prototypal inheritance/shared methods approach as each method is created per instance and not shared.
Anyways, off to a review of your code:
this._items[key] = this[key] = value;
I'm not sure why you want to add the key-value pair as a property of the cache object. I'm pretty sure this is why you have to guard against overriding your methods. I suggest you don't. Make your object just an interface. Don't put your data on it. Just put it in _items
.
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
});
});
map
is a special iterator method. It runs on each array item and expects a return value for each item to form the new array it creates. If you just end us using it to loop through, then forEach
is a better choice. Less confusing.
Additionally, naming variables properly is a must. Explicit is better than implicit, and naming your variables explicitly is better for readability than having to guess what they're for. It takes 5 seconds for a developer to know a purpose of a variable if named properly, rather than 5 mins because the developer has to read through the implementation.
this.delete = function(key) {
IIRC, IE8 and some other browsers have issues when using some keywords as property/function names. Best use alternative names like remove
.
Anyways, here's a simplified implementation. Should be straightforward:
function LruCache(capacity){
this._capacity = capacity || 1;
this._accessMap = [];
this._items = {};
}
LruCache.prototype.cache = function(key, value){
if(this._accessMap.length >= this._capacity) this.removeOldest();
this._accessMap.push(key);
this._items[key] = value;
};
LruCache.prototype.remove = function(key){
this._accessMap.splice(this._accessMap.indexOf(key), 1);
delete this._items[key];
};
LruCache.prototype.removeOldest = function(){
var oldestKey = this._accessMap.shift();
delete this._items[oldestKey];
};
LruCache.prototype.getCapacity = function(){
return this._capacity;
};
LruCache.prototype.getSize = function(){
return this._accessMap.length;
};
If you really want privates by way of closures and throw away the entire concept of shared methods, you can do this:
function LruCache(capacity){
var _capacity = capacity || 1;
var _accessMap = [];
var _items = {};
this.cache = function(key, value){
if(this._accessMap.length >= this._capacity) this.removeOldest();
this._accessMap.push(key);
this._items[key] = value;
};
this.remove = function(key){
this._accessMap.splice(this._accessMap.indexOf(key), 1);
delete this._items[key];
};
this.removeOldest = function(){
var oldestKey = this._accessMap.shift();
delete this._items[oldestKey];
};
this.getCapacity = function(){
return this._capacity;
};
this.getSize = function(){
return this._accessMap.length;
};
}