1

Is there a way to chain the following methods from Cache class

cache = cache.getKey(key) || cache.setKey(key).get(key); // cache = cache.getKey(key) || cache.setKey(key).getKey(key);

I know we have native methods Map.prototype​.set() and Map.prototype​.get() but I want to implement it this way. Let me know if you have any suggestions.

function isObject(arg) {
  const typeOfObj = typeof arg;
  return (typeOfObj === 'object' || typeOfObj === 'function') && arg !== null;
}

class Cache {
  constructor() {
    this.map = new Map();
    this.weakmap = new WeakMap();
  }

  setKey(key) {
    const map = this[isObject(key) ? 'weakmap' : 'map'];
    return map.set(key, new Cache());
  }

  getKey(key) {
    const map = this[isObject(key) ? 'weakmap' : 'map'];
    return map.get(key);
  }
}

function getCache(args, cache) {
  for (const key of args) {
    cache = cache.getKey(key) || cache.setKey(key).get(key);
    // cache = cache.getKey(key) || cache.setKey(key).getKey(key);
  }
  return cache;
}

function memoize(fn) {
  const cache = new Cache();
  return (...args) => {
    const item = getCache(args, cache);

    if (Reflect.has(item, 'value')) {
      return item.value;
    }

    return (item.value = fn(args));
  };
}

let counter = 1;
function foo() {
  counter += 1;
  return counter;
}

const id1 = Symbol('id');
const id2 = Symbol('id');

const memoizedFoo = memoize(foo);
console.log(memoizedFoo(id1)); // 2
console.log(memoizedFoo(id1)); // 2
console.log(memoizedFoo(id2)); // 3
console.log(memoizedFoo(id2)); // 3

Any help is greatly appreciated.

FeaturedSpace
  • 479
  • 3
  • 18
John John
  • 1,305
  • 2
  • 16
  • 37
  • 2
    `setKey` should return `this`. Is there any reason for doing that, though? I mean, what's the goal? – briosheje May 31 '19 at 15:02
  • What do you mean by "chain"? Show an example of what that would look like. – Heretic Monkey May 31 '19 at 15:02
  • @HereticMonkey the example is shown at the beginning of the question. here it is / `cache = cache.getKey(key) || cache.setKey(key).getKey(key);` – John John May 31 '19 at 15:05
  • Possible duplicate of [Chaining methods with javascript](https://stackoverflow.com/questions/34898711/chaining-methods-with-javascript) – Heretic Monkey May 31 '19 at 15:07
  • @briosheje I am doing it purely for experimenting with the code – John John May 31 '19 at 15:07
  • 1
    @JohnJohn then just keep in mind that to accomplish that, you should always return an object. In your case, returning `this` is enough, as it will carry the instance on for the next call. However, I would suggest you to read this: https://stackoverflow.com/questions/1103985/method-chaining-why-is-it-a-good-practice-or-not in order to have a wider opinion about method chaining. – briosheje May 31 '19 at 15:10
  • For a cache mechanism, you could just have a single `getOrSet(key)` method, or one in addition to `get` and `set`, that returns the cached item or creates it and then returns it. Chaining in this situation isn't really offering you any advantages over a simple method. – Cᴏʀʏ May 31 '19 at 15:31

1 Answers1

1

Unfortunately, if you're trying to "GET" a key, you cannot return the map, as you're asking for the key, so it must return the key. So you can't chain that method. But any method that shouldn't return something by default (IE would be void), we can do this:

cache = cache.getKey(key) || cache.setKey(key).get(key);

This will return a boolean, as the || symbol means return true if either is true.

But if you'd like to do the sort of chaining that JQuery does, that's easily achievable! What you want to do is return this or the object in every method.

Like so:

function isObject(arg) {
  const typeOfObj = typeof arg;
  return (typeOfObj === 'object' || typeOfObj === 'function') && arg !== null;
}

class Cache {
  constructor() {
    this.map = new Map();
    this.weakmap = new WeakMap();
  }

  setKey(key) {
    const map = this[isObject(key) ? 'weakmap' : 'map'];
    map.set(key, new Cache());
    return this; // HERE'S THE IMPORTANT PART
  }
}

let counter = 1;
function foo() {
  counter += 1;
  return counter;
}

const id1 = Symbol('id');
const id2 = Symbol('id');

const memoizedFoo = memoize(foo);
console.log(memoizedFoo(id1)); // 2
console.log(memoizedFoo(id1)); // 2
console.log(memoizedFoo(id2)); // 3
console.log(memoizedFoo(id2)); // 3
FeaturedSpace
  • 479
  • 3
  • 18