向对象内数组添加数据时所有数组同步更新问题排查
问题根源:数组的引用类型特性
你碰到的问题其实是JavaScript里一个很常见的坑——数组属于引用类型,你在第一个循环里给每个日期对象的data属性赋值的都是同一个hourlyUpload数组的引用,而不是创建新的数组副本。这就导致所有日期的data其实指向的是同一个内存地址的数组,不管你修改哪个日期的data,其他日期的data都会跟着变,最后所有数据集的数据自然就完全一样了。
具体错误点
看你第一个循环里的这段代码:
dailyUploadtemp.push({ label: day, data: hourlyUpload })
这里直接把hourlyUpload数组传进去,本质是把数组的引用赋值给了每个对象的data属性,所有对象共享同一个数组。
修复方案
只需要在每次添加新日期的时候,创建一个hourlyUpload的新副本,而不是直接引用原数组。可以用ES6的扩展运算符[...hourlyUpload],或者数组的slice()方法来生成副本:
修改第一个循环里的push语句为:
dailyUploadtemp.push({ label: day, data: [...hourlyUpload] }) // 或者用slice():data: hourlyUpload.slice()
修正后的完整代码
以下是调整后的完整代码,只改了关键的引用问题,保留了你原来的分步逻辑:
//my sample Data let Uploads = [{ user: 'user1', files: [{ uploadToServerTime: '21:12:2018 09:15:00' }] }, { user: 'user2', files: [{ uploadToServerTime: '22:12:2018 10:17:00' }] }, { user: 'user3', files: [{ uploadToServerTime: '22:12:2018 09:14:00' }] }] //the hourlyUpload Array has a length of 24 for each hour of the day let hourlyUpload = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; let dailyUploadtemp = []; let dailyUpload = []; let hour; let day; let uploadMoment; for (let x of Uploads) { if (x.hasOwnProperty('files')) { for (let y of x.files) { if (y.hasOwnProperty('uploadToServerTime')) { uploadMoment = moment(y.uploadToServerTime, ['DD.MM.YYYY HH:mm:ss']); day = uploadMoment.format('DD.MM.YYYY'); // 关键修改:创建数组副本,而不是引用原数组 dailyUploadtemp.push({ label: day, data: [...hourlyUpload] }) } } } } dailyUpload = _.uniqBy(dailyUploadtemp, 'label'); //now I have an array of Objects with a set of empty hours for each day an upload has taken place for (let x of Uploads) { if (x.hasOwnProperty('files')) { for (let y of x.files) { if (y.hasOwnProperty('uploadToServerTime')) { uploadMoment = moment(y.uploadToServerTime, ['DD.MM.YYYY HH:mm:ss']); hour = uploadMoment.format('H'); day = uploadMoment.format('DD.MM.YYYY'); for (let z of dailyUpload) { if (z.label === day) { z.data[hour] = (z.data[hour] + 1); } } } } } } let ctx = document.getElementById("myChart").getContext("2d"); let myChart = new Chart(ctx, { type: 'line', data: { labels: ['00:00','01:00','02:00','03:00','04:00','05:00','06:00','07:00','08:00','09:00','10:00','11:00','12:00','13:00','14:00','15:00','16:00','17:00','18:00','19:00', '20:00','21:00','22:00','23:00'], datasets: dailyUpload }, options: { //responsive: false, animation: { duration: 1000, easing: 'easeOutQuad' }, scales: { xAxes: [{ type: 'time', time: { parser: "HH:mm", unit: 'hour', unitStepSize: 1, displayFormats: { 'minute': 'HH:mm', 'hour': 'HH:mm', min: '00:00', max: '23:59' } } }] } } });
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script> <p>There should be two different lines, but I only get two lines with the same datapoints</p> <canvas id="myChart" width="800" height="400"></canvas>
这样修改后,每个日期的data都是独立的数组,统计上传量时就只会修改对应日期的数据,最终Chart.js就能渲染出两条不同的曲线了。
内容的提问来源于stack exchange,提问作者Torf
相关产品推荐
相关产品推荐

