使用数组的记忆功能比较符号

时间:2019-05-21 23:48:27

标签: javascript

我正在尝试使用备忘录功能比较两个不同的Symbol()。到目前为止,id1 === id2 - true应该是false。我知道问题出在哪里,但不确定如何解决。让我知道您是否有任何想法或如何解决。这个没有Map

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

function memoize(fn) {
  const cache = {};
  return (...args) => {
    const stringifiedArgs = JSON.stringify(
      args.map(arg => (typeof arg === 'symbol' ? arg.toString() : arg))
    );
    const result = (cache[stringifiedArgs] = !cache.hasOwnProperty(
      stringifiedArgs
    )
      ? fn(...args)
      : cache[stringifiedArgs]);
    return result;
  };
}

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

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

最终解决方案 我正在添加最终解决方案,待处理工作完成。您可以在底部看到所有测试。

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

function symbolId(symbol) {
  let id = symbolId.list.indexOf(symbol);
  if (id < 0) id = symbolId.list.push(symbol) - 1; // push returns new length.
  return `\uF8FF${id}`; // F8FF is the last "private use" in the BMP.
}
symbolId.list = []; // Yes, it is possible to add things on a function.

function stringifyArgs(args) {
  return JSON.stringify(args, (key, value) => {
    const toStringVar = Object.prototype.toString.call(value);
    const objectTypes = [
      '[object Symbol]',
      '[object RegExp]',
      '[object Function]',
      '[object Object]'
    ];
    return objectTypes.includes(toStringVar) //if
      ? symbolId(value)
      : toStringVar === '[object Undefined]' //if
      ? String(value) //use String() for [object Undefined] - toString() Does not work
      : value;
  });
}

function memoize(fn) {
  const cache = {};
  return (...args) => {
    const stringifiedArgs = stringifyArgs(args);
    if (!(stringifiedArgs in cache)) {
      //!cache.hasOwnProperty(stringifiedArgs)
      cache[stringifiedArgs] = fn(...args);
    }
    return cache[stringifiedArgs];
  };
}



const id1 = Symbol('id');
const id2 = Symbol('id');
const re = new RegExp('ab+c');
const ex = new RegExp('ab+c');
const obj1 = { a: 1 };
const obj2 = { a: 1 };
let typeFnc1 = (a, b) => {
  let c = a + b;
};
let typeFnc2 = (c, d) => {
  let f = c + d;
};
let typeFnc3 = () => {};
let typeFnc4 = () => {};

const memoizedFoo = memoize(foo);
console.log(memoizedFoo(id1)); // 2
console.log(memoizedFoo(id1)); // 2
console.log(memoizedFoo(id2)); // 3
console.log(memoizedFoo(id2)); // 3
console.log(memoizedFoo(null)); // 4
console.log(memoizedFoo(null)); //4
console.log(memoizedFoo(undefined)); // 5
console.log(memoizedFoo(undefined)); //5
console.log(memoizedFoo(5)); // 6
console.log(memoizedFoo(5)); // 6
console.log(memoizedFoo(obj1)); // 7
console.log(memoizedFoo(obj1)); // 7
console.log(memoizedFoo(obj2)); // 8
console.log(memoizedFoo(obj2)); // 8
console.log(memoizedFoo(4)); // 9
console.log(memoizedFoo(3, 4, 5, 6)); //10
console.log(memoizedFoo(3, 4, 5, 6)); //10
console.log(memoizedFoo(3, 4, 6)); //11
console.log(memoizedFoo(3, 4, 6)); //11
console.log(memoizedFoo(typeFnc1)); // 12
console.log(memoizedFoo(typeFnc1)); //12
console.log(memoizedFoo(typeFnc2)); // 13
console.log(memoizedFoo(typeFnc2)); //13
console.log(memoizedFoo(typeFnc3)); // 14
console.log(memoizedFoo(typeFnc3)); //14
console.log(memoizedFoo(typeFnc4)); // 15
console.log(memoizedFoo(typeFnc4)); //15
console.log(memoizedFoo(re)); //16
console.log(memoizedFoo(re)); //16
console.log(memoizedFoo(ex)); //17
console.log(memoizedFoo(ex)); //17
console.log(memoizedFoo(id1, [id1, id2])); // 18
console.log(memoizedFoo(id1, [id1, id2])); // 18

2 个答案:

答案 0 :(得分:1)

您的主要问题是,将唯一的符号转换为字符串,然后执行此操作,将获得可选的描述,并且由于具有相同的描述,因此对它们进行字符串化后它们是相同的。符号不应该被字符串化,如果您仍然这样做,并且想知道它们是否不同,则需要为每个符号存储唯一的标识符。

快速且非常脏的函数,用于将每个符号存储在数组中,并以字符串形式返回唯一标识符。

function symbolId(symbol) {
  let id = symbolId.list.indexOf(symbol);
  if (id < 0) id = symbolId.list.push(symbol) - 1; // push returns new length.
  return `\uF8FF${id}`; // F8FF is the last "private use" in the BMP. 
}
symbolId.list = []; // Yes, it is possible to add things on a function.

然后我像这样替换了您的转化:

const stringifiedArgs = JSON.stringify(
  args,
  (key, value) => typeof value === 'symbol' ? symbolId(value) : value
);

完整示例(包含最终解决方案的更新)

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

function symbolId(symbol) {
  let id = symbolId.list.indexOf(symbol);
  if (id < 0) id = symbolId.list.push(symbol) - 1; // push returns new length.
  return `\uF8FF${id}`; // F8FF is the last "private use" in the BMP.
}
symbolId.list = []; // Yes, it is possible to add things on a function.

function memoize(fn) {
  const cache = {};
  return (...args) => {
    const stringifiedArgs = JSON.stringify(args, (key, value) =>
      {
        const toString = Object.prototype.toString.call(value); // Cache toString result
        return (
          toString === '[object Symbol]' ||
          toString === '[object RegExp]' ||
          toString === '[object Function]' ||
          toString === '[object Object]'
          ) ? symbolId(value)
            : toString === '[object Undefined]'
            ? String(value)
            : value
      }
    );
    const result = (cache[stringifiedArgs] = !cache.hasOwnProperty(
      stringifiedArgs
    )
      ? fn(...args)
      : cache[stringifiedArgs]);
    return result;
  };
}
// creating a memoized function for the 'add' pure function
const id1 = Symbol('id');
const id2 = Symbol('id');
const re = new RegExp('ab+c');
const ex = new RegExp('ab+c');
const obj1 = { a: 1 };
const obj2 = { a: 1 };
let typeFnc1 = (a, b) => {
  let c = a + b;
};
let typeFnc2 = (c, d) => {
  let f = c + d;
};
let typeFnc3 = () => {};
let typeFnc4 = () => {};


function test(result, expected) {
  console.log('%s: %s ', result === expected, result );
}
const memoizedFoo = memoize(foo);
test(memoizedFoo(id1),1);
test(memoizedFoo(id1),1);
test(memoizedFoo(id2),2);
test(memoizedFoo(id2),2);
test(memoizedFoo(null),3);
test(memoizedFoo(null),3);
test(memoizedFoo(undefined),4);
test(memoizedFoo(undefined),4);
test(memoizedFoo(5),5);
test(memoizedFoo(5),5);
test(memoizedFoo(obj1),6);
test(memoizedFoo(obj1),6);
test(memoizedFoo(obj2),7);
test(memoizedFoo(obj2),7);
test(memoizedFoo(4),8);
test(memoizedFoo(3, 4, 5, 6),9);
test(memoizedFoo(3, 4, 5, 6),9);
test(memoizedFoo(3, 4, 6),10);
test(memoizedFoo(3, 4, 6),10);
test(memoizedFoo(typeFnc1),11);
test(memoizedFoo(typeFnc1),11);
test(memoizedFoo(typeFnc2),12);
test(memoizedFoo(typeFnc2),12);
test(memoizedFoo(typeFnc3),13);
test(memoizedFoo(typeFnc3),13);
test(memoizedFoo(typeFnc4),14);
test(memoizedFoo(typeFnc4),14);
test(memoizedFoo(re),15);
test(memoizedFoo(re),15);
test(memoizedFoo(ex),16);
test(memoizedFoo(ex),16);
test(memoizedFoo(id1, [id1, id2]),17);
test(memoizedFoo(id1, [id1, id2]),17);

答案 1 :(得分:1)

解决方案 这是我用@some唤醒的最终解决方案。它考虑了不同类型的参数:[object Array],[object Object],[object Function],[object Symbol], [object Undefined], [object Null], [object RegExp]

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

function symbolId(symbol) {
  let id = symbolId.list.indexOf(symbol);
  if (id < 0) id = symbolId.list.push(symbol) - 1; // push returns new length.
  return `\uF8FF${id}`; // F8FF is the last "private use" in the BMP.
}
symbolId.list = []; // Yes, it is possible to add things on a function.

 function stringifyArgs(args) {
  const replacer = (key, value) => {
    const toStringVar = Object.prototype.toString.call(value);
    const objectTypes = [
      '[object Symbol]',
      '[object RegExp]',
      '[object Function]',
      '[object Object]'
    ];
    return objectTypes.includes(toStringVar) //if
      ? symbolId(value)
      : toStringVar === '[object Undefined]' //if
      ? String(value) //use String() for [object Undefined] - toString() Does not work
      : value;
  };

  return JSON.stringify(args, replacer);
}

function memoize(fn) {
  const cache = {};
  return (...args) => {
    const stringifiedArgs = stringifyArgs(args);
    if (!(stringifiedArgs in cache)) {
      //!cache.hasOwnProperty(stringifiedArgs)
      cache[stringifiedArgs] = fn(...args);
    }
    return cache[stringifiedArgs];
  };
}


const id1 = Symbol('id');
const id2 = Symbol('id');
const re = new RegExp('ab+c');
const ex = new RegExp('ab+c');
const obj1 = { a: 1 };
const obj2 = { a: 1 };
let typeFnc1 = (a, b) => {
  let c = a + b;
};
let typeFnc2 = (c, d) => {
  let f = c + d;
};
let typeFnc3 = () => {};
let typeFnc4 = () => {};

const memoizedFoo = memoize(foo);
console.log(memoizedFoo(id1)); // 2
console.log(memoizedFoo(id1)); // 2
console.log(memoizedFoo(id2)); // 3
console.log(memoizedFoo(id2)); // 3
console.log(memoizedFoo(null)); // 4
console.log(memoizedFoo(null)); //4
console.log(memoizedFoo(undefined)); // 5
console.log(memoizedFoo(undefined)); //5
console.log(memoizedFoo(5)); // 6
console.log(memoizedFoo(5)); // 6
console.log(memoizedFoo(obj1)); // 7
console.log(memoizedFoo(obj1)); // 7
console.log(memoizedFoo(obj2)); // 8
console.log(memoizedFoo(obj2)); // 8
console.log(memoizedFoo(4)); // 9
console.log(memoizedFoo(3, 4, 5, 6)); //10
console.log(memoizedFoo(3, 4, 5, 6)); //10
console.log(memoizedFoo(3, 4, 6)); //11
console.log(memoizedFoo(3, 4, 6)); //11
console.log(memoizedFoo(typeFnc1)); // 12
console.log(memoizedFoo(typeFnc1)); //12
console.log(memoizedFoo(typeFnc2)); // 13
console.log(memoizedFoo(typeFnc2)); //13
console.log(memoizedFoo(typeFnc3)); // 14
console.log(memoizedFoo(typeFnc3)); //14
console.log(memoizedFoo(typeFnc4)); // 15
console.log(memoizedFoo(typeFnc4)); //15
console.log(memoizedFoo(re)); //16
console.log(memoizedFoo(re)); //16
console.log(memoizedFoo(ex)); //17
console.log(memoizedFoo(ex)); //17
console.log(memoizedFoo(id1, [id1, id2])); // 18
console.log(memoizedFoo(id1, [id1, id2])); // 18