Array.fill基于引用对象赋值导致的数据绑定问题

58 阅读1分钟

事情是这样的,有这样一个列表选项输入模块:

image.png

在弹框内,其中选项1,选项2是默认的初始项,默认都是无内容,后续用户可以自行添加选项,不保存关闭弹框后,重新打开弹框重新变成默认只有选项1,选项2的初始状态。

const initOptions = new Array(2).fill({input: ''})
export default {
   data() {
       return {
           optionsList: initOptions
       }
   },
   methods: {
       addOption() {
           this.optionsList.push(xxx);
       },
       closePopup() {
           this.optionsList = initOptions
       }
   }
}

这样看起来好像没啥问题,定义一个默认的初始化变量initOptions, 之后如果需要重置optionsList,那么直接进行初始化赋值即可。但是兄弟们,因为fill填充的是引用对象,所以实际情况是:

  1. 因为两个选项都通过双向数据绑定到了optionsList的子项中,两个选项输入内容同步输入,即选项1输入1,选项2也同步展示1;
  2. 添加了选项之后,关闭弹框后,重新打开,还是之前输入内容;

这么神奇的事情也是第一次遇到,于是我模拟了一下数组fill方法,结果让我哭笑不得:

const list = new Array(2).fill({ a: 1 });
console.log(list[0] === list[1]); // true

破案了,我们分析下上面发生问题的原理:

  1. 双向绑定实际上是指向了同一个引用对象,所以两个选项的输入是同步绑定的;
  2. 添加选项的操作,变更实际上也指向了引用对象,用来初始化的initOptions对象被污染了。

之前fill方法用的不多,没想到遇到这么个问题,希望能给看到的读者避坑。