Javascript 使数组中的新元素在 array.push 之后出现在不同的索引中(不像预期的那样在 array.length 索引中)

Posted

技术标签:

【中文标题】Javascript 使数组中的新元素在 array.push 之后出现在不同的索引中(不像预期的那样在 array.length 索引中)【英文标题】:Javascript makes new Element in Array appear in different index after arr.push (not in arr.length index as expected) 【发布时间】:2022-01-08 03:27:52 【问题描述】:

我有一个名为 tasks 的数组。 我有很多任务存储在里面。 示例:

[
  
    "id": "2",
    "taskName": "dswrs",
    "startDate": "1969-12-31T23:00:00.000Z",
    "endDate": "1969-12-31T23:00:55.000Z",
    "duration": "1969-12-31T23:00:55.000Z",
    "categorie": "Processing"
  ,
  
    "id": "1",
    "taskName": "A",
    "startDate": "1969-12-31T23:00:30.000Z",
    "endDate": "1969-12-31T23:00:55.000Z",
    "duration": "1969-12-31T23:00:25.000Z",
    "categorie": "Processing"
  
]

在这里你已经可以看到我的问题了。我在具有 id:1 的元素之后添加了具有 id:2 的元素(使用tasks.push(...)) 所以我希望它是这样的:

    [
       
        "id": "1",
        "taskName": "A",
        "startDate": "1969-12-31T23:00:30.000Z",
        "endDate": "1969-12-31T23:00:55.000Z",
        "duration": "1969-12-31T23:00:25.000Z",
        "categorie": "Processing"
      ,
      
        "id": "2",
        "taskName": "dswrs",
        "startDate": "1969-12-31T23:00:00.000Z",
        "endDate": "1969-12-31T23:00:55.000Z",
        "duration": "1969-12-31T23:00:55.000Z",
        "categorie": "Processing"
      
    ]

仅当新添加的元素比已存在的元素具有lower startDate 时才会出现此问题。 问题出在我的 D3.js 代码中,我用它在甘特图中显示数据。我希望它在gantt.redraw 函数中,因为我在将新数据添加到我的任务数组后直接调用它,但我找不到问题。

 /* global d3 */
    
    d3.gantt = function () 

   var initTimeDomain = function (tasks) 
    console.log(tasks);
    if (timeDomainMode === FIT_TIME_DOMAIN_MODE) 
        if (tasks === undefined || tasks.length < 1) 
            timeDomainStart = new Date(0);
            timeDomainEnd = new Date(10 ** 5);
            return;
        
        var tasksOrder = tasks;
        tasksOrder.sort(function (a, b) 
            return a.endDate - b.endDate;
        );
        timeDomainEnd = tasksOrder[tasksOrder.length - 1].endDate;
        tasksOrder.sort(function (a, b) 
            return a.startDate - b.startDate;
        );
        timeDomainStart = tasksOrder[0].startDate;
    
;
    
        function gantt (tasks) 
            initTimeDomain();
            initAxis();
    
            var svg = d3.select('svg')
                .attr('class', 'chart')
                .attr('width', width + margin.left + margin.right)
                .attr('height', height + margin.top + margin.bottom)
                .append('g')
                .attr('class', 'gantt-chart')
                .attr('width', width + margin.left + margin.right)
                .attr('height', height + margin.top + margin.bottom)
                .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')');
    
            svg.selectAll('.chart')
                .data(tasks, keyFunction).enter()
                .append('rect')
                .attr('rx', 5)
                .attr('ry', 5)
                .attr('class', function (d) 
                    if (taskCategorie[d.categorie] == null)  return 'bar-killed'; 
                    return taskCategorie[d.categorie];
                )
                .attr('y', 0)
                .attr('transform', rectTransform)
                // ----.attr('height', function (d)  return y.rangeBand(); )
                .attr('height', function (d)  return y.bandwidth(); )
                .attr('width', function (d) 
                    return (x(d.endDate) - x(d.startDate));
                );
    
            svg.append('g')
                .attr('class', 'x axis')
                .attr('transform', 'translate(0, ' + (height - margin.top - margin.bottom) + ')')
                .transition()
                .call(xAxis);
    
            svg.append('g').attr('class', 'y axis').transition().call(yAxis);
    
            return gantt;
        ;
    
        gantt.redraw = function (tasks) 
            console.log("TASKS IN REDRAW: ")
            console.log(tasks);
            initTimeDomain(tasks);
            initAxis();
    
            var svg = d3.select('svg');
    
            var ganttChartGroup = svg.select('.gantt-chart');
            var rect = ganttChartGroup.selectAll('rect').data(tasks, keyFunction);
    
            var div = d3.select('body').append('div')
                .attr('class', 'tooltip-donut')
                .style('opacity', 0);
    
            rect.enter()
                .insert('rect', ':first-child')
                .on('mouseover', function (d, i) 
                    d3.select(this).transition()
                        .duration('50')
                        .attr('opacity', '.85');
                    // Makes the new div appear on hover:
                    div.transition()
                        .duration(50)
                        .style('opacity', 1);
                    div.html(['Taskname: ' + i.taskName, 'Start: ' + i.startDate.toLocaleTimeString(), 'Ende: ' + i.endDate.toLocaleTimeString()].join('<br/>'))
                        .style('left', (d.pageX + 10) + 'px')
                        .style('top', (d.pageY - 15) + 'px');
                )
                .on('mouseout', function (d, i) 
                    d3.select(this).transition()
                        .duration('50')
                        .attr('opacity', '1');
                    div.transition()
                        .duration('50')
                        .style('opacity', 0);
                )
                .attr('rx', 5)
                .attr('ry', 5)
                .attr('class', function (d) 
                    if (taskCategorie[d.categorie] == null)  return 'bar-killed'; 
                    return taskCategorie[d.categorie];
                )
                .transition()
                .attr('y', 0)
                .attr('transform', rectTransform)
                .attr('height', function (d)  return y.bandwidth(); )
                .attr('width', function (d) 
                    return (x(d.endDate) - x(d.startDate));
                );
    
            rect.transition()
                .attr('transform', rectTransform)
                .attr('height', function (d)  return y.bandwidth(); )
                .attr('width', function (d) 
                    return (x(d.endDate) - x(d.startDate));
                );
    
            rect.exit().remove();
    
            svg.select('.x').transition().call(xAxis);
            svg.select('.y').transition().call(yAxis);
    
            console.log("TASKS NACH REDRAW: ")
            console.log(tasks);
            return gantt;
        ;
    
        gantt.margin = function (value) 
            if (!arguments.length)
                return margin;
            margin = value;
            return gantt;
        ;
    
        gantt.timeDomain = function (value) 
            if (!arguments.length)
                return [timeDomainStart, timeDomainEnd];
            timeDomainStart = +value[0], timeDomainEnd = +value[1];
            return gantt;
        ;
      
        return gantt;
    ;

【问题讨论】:

那里有很多代码。我认为如果您将代码缩减到最低限度以使其仍然重现问题,您将获得更大的成功。我的意思是,将对象推入数组与 I/O 方面几乎没有关系,例如 SVG 技术……填充、过渡等。 这可能与您在initTimeDomain 中所做的tasksOrder 的排序无关...? 【参考方案1】:

问题出在initTimeDomain 方法中。 在那里,您正在使用 var tasksOrder = tasks; 创建对 tasks 数组的新引用,然后按日期对 tasksOrder 进行排序。 问题在于 javascript 对象和数组是引用,这意味着 tasksOrdertasks 指向同一个数组。 说的很简单,修改一个也会改变另一个。

如果你不想要这个,你需要创建一个真实的副本,像这样:

var tasksOrder = tasks.slice();  

【讨论】:

以上是关于Javascript 使数组中的新元素在 array.push 之后出现在不同的索引中(不像预期的那样在 array.length 索引中)的主要内容,如果未能解决你的问题,请参考以下文章

如何将一个数组推入另一个数组元素中作为 JavaScript 中的新属性? [复制]

JavaScript常用数组方法

列表和键

比较两个对象数组,并将匹配值的元素排除到JS中的新数组中

javascript更改数组中的元素[重复]

2021-09-20:给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O