通过“ this”关键字

问题描述

嘿,我开始阅读有关Javascript ES6类的文章,所以尝试了一些事情

这是我的ProductItem类,用于呈现每个产品

class ProductItem {
  constructor(product) {
    this.product = product;
  }
  addToCart() {
    console.log("adding product to cart",this.product);
    ShoppingCart.addProduct(this.product);
  }
  render() {
    const prodEl = document.createElement("li");
    prodEl.className = "product-item";
    prodEl.innerHTML = `
      <div>
        <img src="${this.product.imageUrl}" alt="${this.product.title}" >
        <div class="product-item__content">
          <h2>${this.product.title}</h2>
          <h3>\$${this.product.price}</h3>
          <p>${this.product.description}</p>
          <button>Add to Cart</button>
        </div>
      </div>
    `;
    const addCardButton = prodEl.querySelector("button");
    addCardButton.addEventListener("click",this.addToCart.bind(this));
    return prodEl;
  }
}

在另一个类中,我们像这样循环和实例化该类

for (const prod of this.products) {
      const productItem = new ProductItem(prod);
      const prodEl = productItem.render();
      prodList.append(prodEl);
    }

所以现在的问题是,当我单击按钮时,我做了另一个名为“ ShoppingCart”的类来将产品添加到购物车,就像

class ShoppingCart {
  constructor(items){
    console.log(this)
    this.items=items
  }
  static addProduct(product) {
    console.log(this);
    this.items.push(product);
    this.totalOutput = `<h2>Total Amount: ${1}</h2>`;
  }


}

当我读取静态方法时,无需实例化类即可调用 所以我所做的就是当我在“ ProductItem”类中单击按钮时 我调用了fn(),然后您可以在该函数中看到我所做的事

addToCart() {
    console.log("adding product to cart",this.product);
    ShoppingCart.addProduct(this.product);
  }

但这给了我一个错误

未捕获的TypeError:无法读取未定义的属性“ push”

并且当我在addProduct中使用“ this”控制台时,我看到一些奇怪的输出结果

> class ShoppingCart {   constructor(items){
>     console.log(this)
>     this.items=items   }   static addProduct(product) {
>     console.log(this);
>     this.items.push(product);
>     this.totalOutput = `<h2>Tot…........

解决方法

问题是this.items.push(product)试图将产品推入this.items,但是您从未初始化this.items,因此其值为undefined。构造函数仅在创建类的新实例时执行,而对于类本身不执行。

要解决该问题,您必须在items上定义一个静态ShoppingCart属性:

class ShoppingCart {
  static items = [];

  static addProduct(product) {
    this.items.push(product);
    this.totalOutput = `<h2>Total Amount: ${1}</h2>`;
  }
}
,

解决此类问题的基本方法是通过事件将模块或依赖项(在此类模块之间)解耦,以便以最大的转储/不可知论/干净的方式实现每个模块。

对于OP的示例代码,此答案是将document误用作custom events事件总线

用于引导模型数据的事件总线不一定是 DOM 的一部分。应该鼓励自己构建这样的抽象或使用提供这种实用程序/功能的众多可用库之一。

我个人对模块的结构仍然不满意,因为模型和视图相关代码之间的混合仍然太疯狂了。购物车模块。但是 decoupling 是最基本的方法,可以以一种更干净的代码来工作。

但是现在还应该清楚的是...任何摆脱静态addProduct的方法(...直接固定到ShoppingCart命名空间的方法都不可能访问通过ShoppingCart的{​​{1}}实例并将该字母作为实例方法,可能会更有帮助,因为网页往往呈现的不仅仅是一个代表购物车。

this
// e.g. module ... view/ShoppingCart.js

/*export */function handleAddProductToBoundCart(evt) {
  const shoppingCart = this;
  shoppingCart.addProduct(evt.detail.product);
}

/*export */class ShoppingCart {
  constructor(elmRoot,items) {
    this.elmRoot = elmRoot;
    this.items = items;
    this.renderItemCount();
  }
  renderItemCount() {
    this.elmRoot.innerHTML = `<h2>Total Amount: ${ this.items.length }</h2>`;
  }
  addProduct(product) {
    this.items.push(product);
    this.renderItemCount();

    console.log('ShoppingCart :: addProduct :: product :',product);
  }
  
}
// -----


// e.g. module ... view/ProductItem.js

function handleAddBoundProductItem() {
  const productItem = this;
  const customEvent = new CustomEvent("addtocart",{ detail: { product: productItem } });
  document.dispatchEvent(customEvent);
}

/*export */class ProductItem { 
  constructor(product) {
    this.product = product;
  }
  render() {
    const prodEl = document.createElement("li");
    prodEl.className = "product-item";
    prodEl.innerHTML = `
      <div>
        <img src="${this.product.imageUrl}" alt="${this.product.title}" >
        <div class="product-item__content">
          <h2>${this.product.title}</h2>
          <h3>\$${this.product.price}</h3>
          <p>${this.product.description}</p>
          <button>Add to Cart</button>
        </div>
      </div>
    `;
    const addCardButton = prodEl.querySelector("button");
    addCardButton.addEventListener("click",handleAddBoundProductItem.bind(this));
    return prodEl;
  }
}
// -----


// some product list model data from wherever it came from ...

const productList = [{
  imageUrl: '',title: 'Product A',price: '12.30 Currency',description: 'best whatsoever'
},{
  imageUrl: '',title: 'Product B',price: '450.00 Currency',description: 'most expensive'
}];
// -----


// render functionality from yet another view module ...

// ... import statements ...

const cartView = document.createElement('div');
document.body.appendChild(cartView);

const shoppingCart = new ShoppingCart(cartView,[]);
document.addEventListener('addtocart',handleAddProductToBoundCart.bind(shoppingCart));

// ...
// ...

const prodListView = document.createElement('ul');
document.body.appendChild(prodListView)

//for (const prod of this.products) {
for (const product of productList) {

  const productItem = new ProductItem(product);
  const prodEl = productItem.render();

  // prodList.append(prodEl);

  prodListView.append(prodEl);
}

// additional cart,just in order to demonstrate the appoache's capabilities ...

const miniCartView = document.createElement('div');
document.body.appendChild(miniCartView);

const miniCart = new ShoppingCart(miniCartView,handleAddProductToBoundCart.bind(miniCart));

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...