繁体   English   中英

通过“this”关键字访问静态方法中的类属性

[英]Access a Class property within the static method by "this" keyword

嘿伙计们,我开始阅读有关 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);
  }

但这给了我错误

未捕获的类型错误:无法读取未定义的属性“推送”

而且当我在 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 构造函数仅在您创建类的新实例时执行,而不是为类本身执行。

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

class ShoppingCart {
  static items = [];

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

解决此类问题的基本方法是通过事件解耦模块或依赖项(跨此类模块) ,以便以尽可能多的转储/不可知/干净的方式实现每个模块。

对于 OP 的示例代码,此答案以某种方式将document误用为自定义事件的事件总线

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

就我个人而言,我仍然对模块的结构不满意,因为在购物车模块中仍然存在模型和视图相关代码的过度混合。 但是解耦是最基础的,可以朝着更干净的代码工作。

但是现在还应该清楚的是……任何摆脱静态addProduct的方法(……直接固定到ShoppingCart命名空间的方法都没有机会通过this访问ShoppingCart实例……)并使写一个实例方法可能会更有帮助,因为当时网页往往呈现的不仅仅是一个代表购物车的视图。

 // eg 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); } } // ----- // eg 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, []); document.addEventListener('addtocart', handleAddProductToBoundCart.bind(miniCart));
 .as-console-wrapper { min-height: 100%!important; width: 50%; top: 0; left: auto!important; bottom: auto!important; } h2, h3, p, ul, button { font-size: .85em; margin: 1px 0; } h2 { font-size: .7em; } li { margin-bottom: 3px; }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM