代码之家  ›  专栏  ›  技术社区  ›  Eugene Barsky

返回闭包的数组/对象公开其词汇上下文:在javascript中处理的最佳方法?

  •  1
  • Eugene Barsky  · 技术社区  · 6 年前

    我想这可能是一个副本,但我还没有找到一个解释。

    这是我的示例代码:

    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] ,然后阻止内部访问 MaCeCalEngEn() .

    我的问题是:这是解决这个问题的正确方法吗?有更好的方法吗?可能我不明白发生了什么…

    2 回复  |  直到 6 年前
        1
  •  1
  •   CertainPerformance    6 年前

    一种选择是使用 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'));

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

    Uncaught TypeError: Cannot assign to read only property '1' of object '[object Array]
    
        2
  •  1
  •   briosheje    6 年前
    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])) 会起作用。

    诀窍是执行parse和stringify将创建原始对象的新副本,因此原始对象不会受到任何影响。当然,您可以使用其他方法来克隆对象,您可以在这里找到更多信息: What is the most efficient way to deep clone an object in JavaScript?

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