【发布时间】:2022-01-05 05:23:00
【问题描述】:
我正在开发一个普通的 JS / jQuery 应用程序,该应用程序从会话存储中获取数据并将其显示在浏览器中。我创建了一个“Box”类,它代表浏览器页面上的一个框(即 html 卡)。构造函数具有各种属性,如name: this.name 等。
有两种不同类型的框——组和主题——所以我创建了两个子类class GroupBox extends Box 和class SubjectBox extends Box。
这是设计的工作方式:在初始页面加载时,我们调用函数displayGroupBoxes 来填充新的 GroupBox。该函数遍历会话存储中的一堆数据,并在循环的每次迭代中创建一个new GroupBox()。在类构造函数中备份,每次实例化一个新的 GroupBox 时,我们都会创建 HTML 标记来显示数据并将它们附加到页面上。该 DOM 操作代码位于在类构造函数中调用的 GroupBox 类方法中。
还有一点,每个 GroupBox 都有关联的“主题”,这就是我们有 SubjectBox 类的原因。当用户点击 GroupBox 时,我们会找到相关的 SubjectBox 对象并将它们显示在页面上。
好的,所以这里一切正常,除了我遇到了一个问题。 displayGroupBoxes() 函数获取关联的主题并将它们传递回构造函数,以便为数据创建 HTML 标记并将其附加到页面。当所有 DOM 操作代码都在构造函数中时,我得到了这个工作。然而,我收到了一位同事的代码审查,他们说最好将 DOM 操作代码分离到一个类方法中以提高可读性,即它不全部在构造函数中。完成此操作后,我将无法再访问从 displayGroupBoxes 函数传递的数据。
我知道这里有很多非常特定于项目的代码,但我希望通过这种解释,有人可能能够查看代码并理解为什么我无法访问 displayGroupBoxes 中的属性GroupBox 类方法createNewElements 中的函数。
//////////////////////////////////////////////////////////////////////////////
// CLASSES \\
//////////////////////////////////////////////////////////////////////////////
/////////////////////////
// BOX Parent Class
/////////////////////////
/**
* Represents a box.
* @constructor
* @param {object} boxOptions - An object to hold our list of constructor args
* @param {string} name - Name associated with account
* @param {string} type - Type associated with account
*/
class Box {
constructor(boxOptions) {
this.name = boxOptions.name;
this.type = boxOptions.type;
this.logo = boxOptions.logo;
}
}
/////////////////////////////
// SubjectBox SubClass
////////////////////////////
/**
* Represents a SubjectBox. These are subjects, like individual people, associated with a given group. We don't see these on initial page load. They get created (or if already created, toggled to hidden/visible) when a user clicks on a group.
*/
class SubjectBox extends Box {
constructor(subjectOptions) {
super({
name: subjectOptions.name,
type: subjectOptions.type,
logo: subjectOptions.logo,
});
this.name = subjectOptions.name;
this.type = subjectOptions.type;
this.logo = subjectOptions.logo;
this.subjectId = subjectOptions.subjectId;
this.container = document.createElement("div");
// ---> a bunch of code to create HTML tags and append to page
}
/////////////////////////
// GroupBox SubClass
/////////////////////////
/**
* Represents a GroupBox. New group boxes are instantiated when the "displayGroupBoxes()" function is called. This is what we see on initial page load.
* @constructor
* @param {object} groupOptions - An object to store our list of constructor args
* @param {array} subjectBoxes - An array to store subject boxes so that once they've been instantiated, we can store them here and then toggle to hidden/visible.
*/
class GroupBox extends Box {
constructor(groupOptions) {
super({
name: groupOptions.name,
type: groupOptions.type,
logo: groupOptions.logo,
});
// Use this array to store the subject boxes that have already been created, so if the user clicks on the same subject, we can grab those boxes and show them rather than rebuilding.
this.subjectBoxes = [];
this.name = groupOptions.name;
this.type = groupOptions.type;
this.logo = groupOptions.logo;
// Create HTML Elements and Append To Page
this.createGroupBox();
}
// Class method to create HTML tags and append to page
createGroupBox() {
// Create container div for box
const newGroupBox = document.createElement("div");
newGroupBox.className = "group-box-container";
// ----> A bunch of code here to create name and title, append to page. Now we need to display image icons of the subjects that are associated with the group:
// Container for SubjectBox Icons
const mainContainer = document.createElement("div");
mainContainer.className = "box-main-container";
// Icons
const iconsContainer = document.createElement("div");
iconsContainer.className = "box-icons-container";
// Loop through Icons object, which contains arrays of subjects, to create an img tag for each one and append to iconsContainer.
//// ------ >> this.subjectIcons is now returning undefined << \\
let icons = this.subjectIcons;
for (let i in icons) {
let iconDiv = document.createElement("div");
iconDiv.className = "box-icon-div";
let icon = document.createElement("img");
icon.src = icons[i];
icon.className = "box-icon";
iconDiv.append(icon);
iconsContainer.append(iconDiv);
mainContainer.append(iconsContainer);
i++;
}
newGroupBox.append(mainContainer);
/////////////////////////////////////////////////////////////////
// EVENT LISTENER. -- when the user clicks on a GroupBox, it runs a function to show us the subjects associated with that group
////////////////////////////////////////////////////////////////
newGroupBox.addEventListener("click", () => {
/// --> some code to hide the GroupBoxes that are already on the page so we can display SubjectBoxes instead
// build subject boxes
const boxesContainer = document.getElementById("boxes-container");
// Check to see if subject boxes have already been created. If not, instantiate the new subjectBox objects. Otherwise, if they have already been built, loop through and set them to visible
if (!this.subjectBoxes.length) {
// If subject boxes haven't been created yet, meaning if the user hasn't clicked on this group yet, map over the array of subjects passed up from the `displayGroupBoxes()` function and create a `new SubjectBox` object for each item
//! -----> groupOptions.subjects is returning undefined << \\
this.subjectBoxes = groupOptions.subjects.map((subject, i) => {
return new SubjectBox({
name: groupOptions.subjects[i].entry_text,
type: groupOptions.subjects[i].entry_type,
logo: groupOptions.subjects[i].icon_link,
subjectId: groupOptions.subjects[i].subject_id,
// Set the container for HTML
container: boxesContainer,
});
});
// Otherwise if subject boxes have already been created previously, toggle them to visible
} else {
for (const box of this.subjectBoxes) {
box.show();
}
}
// Append group box to document inside the same container we created for GroupBoxes:
// -------> groupOptions.container is returning undefined ----- \\
groupOptions.container.append(newGroupBox);
}
}
这是上面代码块中引用的displayGroupBoxes()函数:
// --------- Populate Group Boxes --------- \\
function displayGroupBoxes() {
// Initialize array to hold collection of group boxes
let groupBoxes = [];
// Grab the "boxes-container" div from HTML and set it to variable "boxesContainer"
const boxesContainer = document.getElementById("boxes-container");
// Loop through the data to grab all the "B" type group boxes
// Create a new GroupBox object for each item in the array
for (let arr in data) {
if (data[arr].entry_type === "B") {
// Find all "Subject" ("P") boxes associated with item and store in variable "subjectGroup". Then grab all the icon image URL's
let subjectGroup = data.filter(
(group) =>
group.group_number === data[arr].goto_group &&
group.entry_type === "P"
);
let subjectGroupIcons = [];
for (let i in subjectGroup) {
if (
subjectGroup[i].group_number === data[arr].goto_group &&
subjectGroup[i].entry_type === "P"
) {
subjectGroupIcons.push(subjectGroup[i].icon_link);
}
}
// Create new GroupBox objects
let groupBox = new GroupBox({
name: data[arr].entry_text,
type: data[arr].entry_type,
logo: data[arr].icon_link,
//! I'm not able to access these from the new "createGroupBoxes" function...
// Set the container for HTML
container: boxesContainer,
// Pass subjects to GroupBox
subjects: subjectGroup,
// Pass subject icons up to GroupBox
subjectIcons: subjectGroupIcons,
// Pass headers (e.g. "Tennis Group") up to GroupBox
headers: headerGroup,
});
// Push each groupBox object into the groupBoxes array.
// This is just for convenience so we can see all the group boxes easily if we need to.
groupBoxes.push(groupBox);
}
}
}
这里有很多内容,但希望很清楚我想要做什么。我想将container、subjects 和subjectIcons 属性从这个displayGroupBoxes 函数传递给为数据创建HTML 标记并将其附加到页面的类方法。当我在类构造函数中拥有所有的 DOM 操作代码时,这很有效,但是当我将它移到构造函数之外的它自己的类方法中以提高可读性时,除了这些属性被传递之外,一切都正常工作。我一定是把他们叫错了,但我不明白这个问题。
【问题讨论】:
-
"我收到了一位同事的代码审查,他们说最好将 DOM 操作代码分离到一个类方法中以提高可读性,也就是说,它不会全部在构造函数。” - 不仅如此,也不应该从构造函数内部调用。构造函数应该只关心设置实例属性。这样,您的子类可以在调用方法之前完成初始化。
-
"我的代码编辑器在此处添加了括号,我不明白为什么" - 可能是因为您在此处使用了逗号而不是分号。
-
非常有帮助的cmets,理解,我会努力解决这个问题,谢谢!
-
@MickeyVershbow 要跟进 Bergi 的评论,您应该改用 for..of。如果您有机会粘贴这些课程的完整代码,我可以在今天晚些时候或明天提供全面审查
-
@Mulan 好的,我明白你的意思,谢谢,我会这样做!
标签: javascript html jquery oop