为什么当数组元素相同时 Splice 仅删除最后一个元素

Gau*_*rda 3 javascript typescript angular

转到此StackBlitz 链接( Not Working)

转到此StackBlitz 链接( Working Fine)

我的问题是关于Array.splice. 当数组数据不同时,Array.splice 工作正常,但当数组数据相同时,Array.splice仅删除最后一个索引。在这种情况下,splice 会忽略提供的索引以从数组中删除元素。

这两个示例都有通用的 HTML 模板

<div class="container">
    <table class="table table-dark table-striped table-hover">
        <thead>
           <tr>
               <td scope="col"> Index </td>
               <td scope="col"> Value </td>
               <td scope="col"> Action </td>
           </tr>
        </thead>
        <tbody>
            <tr *ngFor="let row of rows; let i = index"  [@itemAnim]>
                <td> {{i}} </td>
                <td>{{row}}</td>
                <td><button class="btn btn-danger" (click)="deleteRow(i)">Delete</button></td>
           </tr>
        </tbody>
    </table>
    <button class="btn btn-primary " (click)="addRow()">Add row</button>
</div>
Run Code Online (Sandbox Code Playgroud)

请参阅此示例按预期工作

index = 1;
rows = [1]; 

addRow() {   
   this.rows.length > 0 ?  this.index ++ : this.index = 1;
   this.rows.push(this.index)
}

deleteRow(row: number) {
   return this.rows.length > 0 ? this.rows.splice(row, 1) : this.index = 1;
}
Run Code Online (Sandbox Code Playgroud)

这不起作用

rows = [1]; 

addRow() {   
  this.rows.push(1)
}

deleteRow(row: number) {
   this.rows.splice(row, 1) ;
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,我仅在单击1时才推送。addButton删除按钮仅从最后一个索引中删除,而不提供行号索引。

我的问题是为什么会发生这种情况?上面的 stackBlitz 链接显示了同样的歧义。

srg*_*rcp 5

因为您实际上正在删除选定的索引,但 Angular 没有任何有关值之间差异的信息,让我们看一个示例:

我们有这个数组:[1, 1, 1, 1] 并且您删除第二项,然后删除之前的角度将看到:

[1, 1, 1, 1]
Run Code Online (Sandbox Code Playgroud)

之后:

[1, 1, 1]
Run Code Online (Sandbox Code Playgroud)

此时 Angular 只知道少了一项,但不知道想要的项,然后 Angular 只删除最后一项。

您需要确保传递不同的值或引用(推荐),然后 Angular 将知道如何区分数组项。

您可以使用以下对象来修复它:{ data: 1 },您的数组将如下所示:

[
  { data: 1 },
  { data: 1 },
  { data: 1 },
  { data: 1 }
]
Run Code Online (Sandbox Code Playgroud)

为什么这会起作用?因为引用不同(值与引用类型),即使数据相同,角度也会看到不同的引用。

这对你有用:

rows = [{ data: 1 }]; 

addRow() {   
  this.rows.push({ data: 1 });
}

deleteRow(row: number) {
  this.rows.splice(row, 1);
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,您始终传递一个带有其自己的引用的新对象。


这另一个例子将不起作用

sameReference = { data: 1 };

rows = [this.sameReference]; 

addRow() {   
  this.rows.push(this.sameReference);
}

deleteRow(row: number) {
  this.rows.splice(row, 1);
}
Run Code Online (Sandbox Code Playgroud)

因为sameReference变量存储的是引用,而不是对象,而 Angular 将不知道(再次)项目之间的差异,此外,当您更改一个元素的数据值时,所有元素都会获得该值,因为只有一个对象被引用 N 次数组内。


这也会起作用

sameReference = { data: 1 };

rows = [{ ...this.sameReference }]; 

addRow() {   
  this.rows.push({ ...this.sameReference });
}

deleteRow(row: number) {
  this.rows.splice(row, 1);
}
Run Code Online (Sandbox Code Playgroud)

因为这里我们将对象的值复制到具有不同引用的新对象中。