闭包返回的数组/对象暴露了其词法上下文:用JavaScript处理的最佳方法?

时间:2018-12-14 08:13:57

标签: javascript closures

我想这可能是重复的,但是我仍然找不到解释。

这是我的示例代码:

const makeCalendar = () => {
  const calendar = {};

  calendar.xmas = ['December', 25];
  calendar.newYear = ['January', 1];

  return (day) => calendar[day];
}

calendar = makeCalendar();
const xmasArray = calendar('xmas');

console.log(calendar('xmas')); // [ 'December', 25 ]

xmasArray[1]++;

console.log(calendar('xmas')); // [ 'December', 26 ]

由于xmasArray的元素是可变的,因此我可以在makeCalendar()范围内更改变量,从而破坏它返回的闭包。我发现解决此问题的唯一方法是返回一个匿名数组[...calendar[day]](而不是calendar[day]),该匿名数组随后会阻塞makeCalendar()内部的访问。

我的问题是:这是解决此问题的正确方法吗?有更好的方法吗?可能我不正确理解发生了什么...

2 个答案:

答案 0 :(得分:1)

const makeCalendar = () => {
  const calendar = {};

  calendar.xmas = ['December', 25];
  calendar.newYear = ['January', 1];

  return (day) => JSON.parse(JSON.stringify(calendar))[day];
}

如果日历对象变得很大,那不是最好的选择,但是仍然可以使用。在这种情况下,即使JSON.parse(JSON.stringify(calendar[day]))也可以使用。

诀窍是进行解析和字符串化将创建原始对象的新副本,因此原始对象将不会受到任何影响。当然,您可以使用其他方式克隆对象,您可以在此处找到更多信息:What is the most efficient way to deep clone an object in JavaScript?

提琴:http://jsfiddle.net/briosheje/317hg6fb/

答案 1 :(得分:1)

一种选择是使用setInterval禁止分配给数组中的任何项目:

Object.freeze

请注意,这种尝试的分配将在严格模式下引发错误:

const makeCalendar = () => {
  const calendar = {
    xmas: ['December', 25],
    newYear: ['January', 1]
  };
  Object.values(calendar).forEach(arr => Object.freeze(arr));
  return (day) => calendar[day];
}

calendar = makeCalendar();
const xmasArray = calendar('xmas');

console.log(calendar('xmas'));

xmasArray[1]++;

console.log(calendar('xmas'));