通过 "this" 关键字在静态方法中访问 Class 属性
Access a Class property within the static method by "this" keyword
大家好,我开始阅读有关 Javascript ES6 classes 的文章,所以正在尝试一些东西
这是我的 ProductItem class,它呈现每个产品
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;
}
}
在另一个 class 中,我们循环并实例化这个 class 就像
for (const prod of this.products) {
const productItem = new ProductItem(prod);
const prodEl = productItem.render();
prodList.append(prodEl);
}
所以现在的问题是我制作了另一个名为“ShoppingCart”的 class 来在我点击按钮时将产品添加到购物车,就像
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: </h2>`;
}
}
据我所知,无需实例化即可调用静态方法 class
所以我所做的是当我点击“ProductItem”中的按钮时 class
我调用了一个 fn() 然后你可以在那个函数中看到我做了什么
addToCart() {
console.log("adding product to cart", this.product);
ShoppingCart.addProduct(this.product);
}
但这给了我错误
Uncaught TypeError: Cannot read property 'push' of undefined
而且当我在 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…........
解决此类问题的基本方法是 通过事件 解耦模块或依赖项(跨此类模块),以便尽可能 dump/agnostic/clean 实现每个模块方式。
对于 OP 的示例代码,此答案以某种方式滥用 document
作为 事件总线 用于 custom events。
用于传输模型数据的事件总线不一定需要是DOM的一部分。应该鼓励人们自己构建这样的抽象,或者使用提供这种抽象的众多可用库之一 utility/functionality.
就我个人而言,我仍然对模块的结构方式不满意,因为模型和视图相关代码的混合仍然过于疯狂。购物车模块。但是 解耦 是一个非常基础的方法,可以使代码更清晰。
但是现在还应该清楚的是......任何摆脱静态 addProduct
的方法(......直接固定到 ShoppingCart
命名空间的方法永远没有机会通过 this
访问 ShoppingCart
实例 ...) 并使字母成为实例方法,可能会有更多帮助,因为网页往往呈现的不仅仅是 [=34= 的一个视图代表]购物车当时。
// 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, []);
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;
}
问题是 this.items.push(product)
试图将产品推入 this.items
,但是您从未初始化 this.items
,所以它的值为 undefined
。构造函数仅在您创建 class 的新实例时执行,但不会为 class 本身执行。
要解决此问题,您必须在 ShoppingCart
:
上定义静态 items
属性
class ShoppingCart {
static items = [];
static addProduct(product) {
this.items.push(product);
this.totalOutput = `<h2>Total Amount: </h2>`;
}
}
大家好,我开始阅读有关 Javascript ES6 classes 的文章,所以正在尝试一些东西
这是我的 ProductItem class,它呈现每个产品
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;
}
}
在另一个 class 中,我们循环并实例化这个 class 就像
for (const prod of this.products) {
const productItem = new ProductItem(prod);
const prodEl = productItem.render();
prodList.append(prodEl);
}
所以现在的问题是我制作了另一个名为“ShoppingCart”的 class 来在我点击按钮时将产品添加到购物车,就像
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: </h2>`;
}
}
据我所知,无需实例化即可调用静态方法 class 所以我所做的是当我点击“ProductItem”中的按钮时 class 我调用了一个 fn() 然后你可以在那个函数中看到我做了什么
addToCart() {
console.log("adding product to cart", this.product);
ShoppingCart.addProduct(this.product);
}
但这给了我错误
Uncaught TypeError: Cannot read property 'push' of undefined
而且当我在 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…........
解决此类问题的基本方法是 通过事件 解耦模块或依赖项(跨此类模块),以便尽可能 dump/agnostic/clean 实现每个模块方式。
对于 OP 的示例代码,此答案以某种方式滥用 document
作为 事件总线 用于 custom events。
用于传输模型数据的事件总线不一定需要是DOM的一部分。应该鼓励人们自己构建这样的抽象,或者使用提供这种抽象的众多可用库之一 utility/functionality.
就我个人而言,我仍然对模块的结构方式不满意,因为模型和视图相关代码的混合仍然过于疯狂。购物车模块。但是 解耦 是一个非常基础的方法,可以使代码更清晰。
但是现在还应该清楚的是......任何摆脱静态 addProduct
的方法(......直接固定到 ShoppingCart
命名空间的方法永远没有机会通过 this
访问 ShoppingCart
实例 ...) 并使字母成为实例方法,可能会有更多帮助,因为网页往往呈现的不仅仅是 [=34= 的一个视图代表]购物车当时。
// 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, []);
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;
}
问题是 this.items.push(product)
试图将产品推入 this.items
,但是您从未初始化 this.items
,所以它的值为 undefined
。构造函数仅在您创建 class 的新实例时执行,但不会为 class 本身执行。
要解决此问题,您必须在 ShoppingCart
:
items
属性
class ShoppingCart {
static items = [];
static addProduct(product) {
this.items.push(product);
this.totalOutput = `<h2>Total Amount: </h2>`;
}
}