Javascript 当函数应该修改新数组时,对象的角度原始数组将被修改

Javascript 当函数应该修改新数组时,对象的角度原始数组将被修改,javascript,angular,typescript,Javascript,Angular,Typescript,我有一组导入到add-product.component.ts的产品 有一个功能,您可以将产品添加到名为basket的购物车中 car.service将做什么?将产品添加到名为basketItems的数组中。若产品已经存在于basketItems数组中,那个么它应该改变basketItem的条目 出于某种原因,篮子和产品都在发生变异,这导致了原产地产品显示在价格上发生变化,而只有篮子应该这样做 我是Angular的新手,我不确定在add-product.component.html中运行(单击)

我有一组导入到add-product.component.ts的产品

有一个功能,您可以将产品添加到名为basket的购物车中

car.service将做什么?将产品添加到名为basketItems的数组中。若产品已经存在于basketItems数组中,那个么它应该改变basketItem的条目

出于某种原因,篮子和产品都在发生变异,这导致了原产地产品显示在价格上发生变化,而只有篮子应该这样做

我是Angular的新手,我不确定在add-product.component.html中运行(单击)=“addToCart(product)”时是否传递了该产品的引用

添加product.component.html

产品系列

<div class="d-flex justify-content-between flex-wrap">
    <div *ngFor='let product of products' class="card mb-5" style="width: 20rem; height: 20rem">
        <img style="object-fit: contain; margin-top: 5%" height="45%" src={{product.image}} [title]='product.name' class="card-img-top" alt={{product.name}}>
        <div class="card-body">
            <div class="mb-3">
                <h5 class="card-title">{{product.name}}</h5>
                <p class="card-text">{{product.description | slice:0:60}}...</p>
            </div>
            <a style="float: left" (click)="addToCart(product)" class="card-link text-primary">Add</a>
            <p style="float: right">{{product.price | currency}}</p>
        </div>
    </div>
</div>
<div>
    <div>
        <table class="table table-striped">
            <thead>
                <tr>
                    <th scope="col"></th>
                    <th scope="col">Count</th>
                    <th scope="col">Product Name</th>
                    <th scope="col">Description</th>
                    <th scope="col">Price</th>
                </tr>
            </thead>
            <tbody>
                <tr *ngFor='let item of basket; index as itemId'>
                    <th scope="row"><button (click)="removeFromCart(itemId)">X</button></th>
                    <th scope="row">{{item.count}}</th>
                    <td>{{item.name}}</td>
                    <td>{{item.description | slice:0:20}}</td>
                    <td>{{item.price | currency}}</td>
                </tr>
            </tbody>
            <thead>
                <tr>
                    <th colspan="3" scope="col"></th>
                    <th scope="col">Total:</th>
                    <th scope="col">{{total | currency}}</th>
                </tr>
            </thead>
        </table>
    </div>
    <button style="float: right" class="btn btn-primary">CHECK OUT</button>
</div>
import { Component, OnInit } from "@angular/core";
import { products } from "../products";
import { CartService } from "../cart.service";

@Component({
  selector: "app-add-product",
  templateUrl: "./add-product.component.html",
  styleUrls: ["./add-product.component.css"]
})
export class AddProductComponent implements OnInit {
  // Array of products to be displayed on screen for the user to add to the basket
  products: object[] = products;

  // The basket is an array of items that were added by the user when they click the add button for that product
  basket: object[];
  total: number;
  constructor(private cartService: CartService) {}

  addToCart(item) {
    this.cartService.addToCart(item);
    this.total = this.basket.reduce((total, item) => total + item.price, 0);
  }

  removeFromCart(index) {
    this.cartService.removeFromCart(index);
    this.basket = this.cartService.getItems();
    this.total = this.basket.reduce((total, item) => total + item.price, 0);
  }

  ngOnInit() {
    this.basket = this.cartService.getItems();
  }
}

import { Injectable } from "@angular/core";
import { AngularFirestore } from "@angular/fire/firestore";
@Injectable()
export class CartService {
  basketItems: object[] = [];

  constructor(private db: AngularFirestore) {}

  addToCart(product) {
    // if product is already in the basket
    // FIX ME basket should mutate and not the product
    for (let i = 0; i < this.basketItems.length; i++) {
      if (product === this.basketItems[i]) {
        let originalPrice =
          this.basketItems[i].price / this.basketItems[i].count;
        this.basketItems[i].count = this.basketItems[i].count + 1;
        this.basketItems[i].price = this.basketItems[i].price + originalPrice;
        console.log("this should not mutate ===>", product, "but it does");
        return;
      }
    }

    this.basketItems.push(product);
  }

  removeFromCart(index) {
    this.basketItems.splice(index, 1);
  }

  getItems() {
    return this.basketItems;
  }

  clearCart() {
    this.basketItems = [];
    return this.basketItems;
  }
}


购物车服务.ts

<div class="d-flex justify-content-between flex-wrap">
    <div *ngFor='let product of products' class="card mb-5" style="width: 20rem; height: 20rem">
        <img style="object-fit: contain; margin-top: 5%" height="45%" src={{product.image}} [title]='product.name' class="card-img-top" alt={{product.name}}>
        <div class="card-body">
            <div class="mb-3">
                <h5 class="card-title">{{product.name}}</h5>
                <p class="card-text">{{product.description | slice:0:60}}...</p>
            </div>
            <a style="float: left" (click)="addToCart(product)" class="card-link text-primary">Add</a>
            <p style="float: right">{{product.price | currency}}</p>
        </div>
    </div>
</div>
<div>
    <div>
        <table class="table table-striped">
            <thead>
                <tr>
                    <th scope="col"></th>
                    <th scope="col">Count</th>
                    <th scope="col">Product Name</th>
                    <th scope="col">Description</th>
                    <th scope="col">Price</th>
                </tr>
            </thead>
            <tbody>
                <tr *ngFor='let item of basket; index as itemId'>
                    <th scope="row"><button (click)="removeFromCart(itemId)">X</button></th>
                    <th scope="row">{{item.count}}</th>
                    <td>{{item.name}}</td>
                    <td>{{item.description | slice:0:20}}</td>
                    <td>{{item.price | currency}}</td>
                </tr>
            </tbody>
            <thead>
                <tr>
                    <th colspan="3" scope="col"></th>
                    <th scope="col">Total:</th>
                    <th scope="col">{{total | currency}}</th>
                </tr>
            </thead>
        </table>
    </div>
    <button style="float: right" class="btn btn-primary">CHECK OUT</button>
</div>
import { Component, OnInit } from "@angular/core";
import { products } from "../products";
import { CartService } from "../cart.service";

@Component({
  selector: "app-add-product",
  templateUrl: "./add-product.component.html",
  styleUrls: ["./add-product.component.css"]
})
export class AddProductComponent implements OnInit {
  // Array of products to be displayed on screen for the user to add to the basket
  products: object[] = products;

  // The basket is an array of items that were added by the user when they click the add button for that product
  basket: object[];
  total: number;
  constructor(private cartService: CartService) {}

  addToCart(item) {
    this.cartService.addToCart(item);
    this.total = this.basket.reduce((total, item) => total + item.price, 0);
  }

  removeFromCart(index) {
    this.cartService.removeFromCart(index);
    this.basket = this.cartService.getItems();
    this.total = this.basket.reduce((total, item) => total + item.price, 0);
  }

  ngOnInit() {
    this.basket = this.cartService.getItems();
  }
}

import { Injectable } from "@angular/core";
import { AngularFirestore } from "@angular/fire/firestore";
@Injectable()
export class CartService {
  basketItems: object[] = [];

  constructor(private db: AngularFirestore) {}

  addToCart(product) {
    // if product is already in the basket
    // FIX ME basket should mutate and not the product
    for (let i = 0; i < this.basketItems.length; i++) {
      if (product === this.basketItems[i]) {
        let originalPrice =
          this.basketItems[i].price / this.basketItems[i].count;
        this.basketItems[i].count = this.basketItems[i].count + 1;
        this.basketItems[i].price = this.basketItems[i].price + originalPrice;
        console.log("this should not mutate ===>", product, "but it does");
        return;
      }
    }

    this.basketItems.push(product);
  }

  removeFromCart(index) {
    this.basketItems.splice(index, 1);
  }

  getItems() {
    return this.basketItems;
  }

  clearCart() {
    this.basketItems = [];
    return this.basketItems;
  }
}


从“@angular/core”导入{Injectable};
从“@angular/fire/firestore”导入{AngularFirestore}”;
@可注射()
出口级货运服务{
篮子项目:对象[]=[];
构造函数(私有数据库:AngularFirestore){}
addToCart(产品){
//如果产品已经在篮子里
//修理我的篮子应该变异,而不是产品
for(设i=0;i”,product,“但它确实如此”);
返回;
}
}
这个。篮子物品。推(产品);
}
removeFromCart(索引){
本规范。篮子项目。拼接(索引,1);
}
getItems(){
归还这个篮子物品;
}
clearCart(){
this.basketItems=[];
归还这个篮子物品;
}
}

为准确度更新此返回一个参考:

 getItems() {
    return this.items;
    console.log(this.items);
  }
你把它分配给你的篮子:

ngOnInit() {
    this.basket = this.cartService.getItems();
  }
所以它们都指向同一个参考点。当您对购物车服务项目进行更改时,您还可以修改购物篮

如果你想避免这种行为,你可以用这样的东西

getItems() {
    return this.items.slice(0); // or [...this.items] a.k.a create a new instance every time
    console.log(this.items);
}
供您编辑:

if (product === this.basketItems[i]) { // you check exactly they have same reference
   let originalPrice =
   this.basketItems[i].price / this.basketItems[i].count;
   this.basketItems[i].count = this.basketItems[i].count + 1;
   this.basketItems[i].price = this.basketItems[i].price + originalPrice;
        console.log("this should not mutate ===>", product, "but it does");
因此,如何修改引用并不重要。它们都会被修改

因此,您正在往返于相同的对象。 您需要做的是:

 this.basketItems.push({...product}); // insert new object everytime
 // and checking part should be
 if (product.id === this.basketItems[i].id) // they are not same object anymore you can not check reference equality.

您编辑了服务中的项目,而期望组件中的产品被编辑?感谢您发布详细问题!你能澄清一下你希望看到什么吗?您可以编辑具有预期结果的问题。是否尝试调试CartService?我已更新了说明。篮子应该发生变化,而不是用户添加到篮子中的产品。我一直将product对象作为引用而不是值传递。我通过使用Object.assign({},product)修复了这个问题