簡體   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