Javascript,如何将属性从方法传递到 class 构造函数?
Javascript, how can I pass properties from method up to class constructor?
我正在开发一个 vanilla JS / jQuery 应用程序,它从会话存储中获取数据并将其显示在浏览器中。我创建了一个“Box”class,代表浏览器页面上的一个框(即 html 卡片)。构造函数具有各种属性,例如 name: this.name
等。
有两种不同类型的框——组和主题——所以我创建了两个子classes class GroupBox extends Box
和class SubjectBox extends Box
。
这是它设计的工作方式:在初始页面加载时,我们调用一个函数 displayGroupBoxes
来填充新的 GroupBox。该函数循环遍历会话存储中的一堆数据,并在循环的每次迭代中创建一个 new GroupBox()
。回到 class 构造函数,每次实例化一个新的 GroupBox 时,我们都会创建 HTML 标签来显示数据并将它们附加到页面。 DOM 操作代码位于 GroupBox
class 方法中,该方法在 class 构造函数中被调用。
还有一件事,每个 GroupBox 都有关联的“主题”,这就是我们有 SubjectBox class 的原因。当用户单击 GroupBox 时,我们会找到关联的 SubjectBox 对象并将它们显示在页面上。
好的,所以这里一切正常,除了我 运行 遇到一个问题。 displayGroupBoxes()
函数获取关联的主题并将它们传递回构造函数以创建数据的 HTML 标记并将其附加到页面。当所有 DOM 操作代码都在构造函数中时,我得到了这个工作。然而,我收到了一位同事的代码审查,他们说最好将 DOM 操作代码分离到 class 方法中以提高可读性,也就是说,这样它就不会全部在构造函数中。执行此操作后,我将无法再访问从 displayGroupBoxes
函数传递过来的数据。
我知道这里有很多非常特定于项目的代码,但我希望通过这种解释,有人可以查看代码并理解为什么我无法访问 displayGroupBoxes
来自 GroupBox class 方法的函数 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
函数传递给 class 方法,该方法创建 HTML 标签数据并将其附加到页面。当我将所有 DOM 操作代码都放在 class 构造函数中时,这起作用了,但是当我将它移到构造函数之外到它自己的 class 方法以提高可读性时,除了这些属性之外,一切都有效通过了。我一定是说错了,但我不明白这个问题。
问题出在 GroupBox
构造函数中,它仅定义名称、类型和徽标。您需要在 class 定义中添加您的其他属性才能使用它们。
constructor(groupOptions) {
super({
name: groupOptions.name,
type: groupOptions.type,
logo: groupOptions.logo,
container: groupOptions.container,
subjects: groupOptions.subjects,
subjectIcons: groupOptions.subjectIcons || [],
headers: groupOptions.headers
});
根据我收到的回复在此分享答案。我标记为正确的答案几乎是正确的,除了不应在 super()
调用中传递属性。我需要在 class 构造函数中定义属性,以便稍后能够从 displayGroupFunctions
向它们传递数据。
现在正如@Bergi 提到的,我仍然需要从 构造函数 外部调用 class 方法 createGroupBox
,但以下代码解决了我原来的问题问题:
class GroupBox extends Box {
// PARAM: groupOptions = {}
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;
-----> new code:
this.container = groupOptions.container;
this.subjects = groupOptions.subjects;
this.subjectIcons = groupOptions.subjectIcons;
this.headers = groupOptions.headers;
----> this should be called from outside the constructor
// Create HTML Elements and Append To Page
this.createGroupBox();
}
我正在开发一个 vanilla JS / jQuery 应用程序,它从会话存储中获取数据并将其显示在浏览器中。我创建了一个“Box”class,代表浏览器页面上的一个框(即 html 卡片)。构造函数具有各种属性,例如 name: this.name
等。
有两种不同类型的框——组和主题——所以我创建了两个子classes class GroupBox extends Box
和class SubjectBox extends Box
。
这是它设计的工作方式:在初始页面加载时,我们调用一个函数 displayGroupBoxes
来填充新的 GroupBox。该函数循环遍历会话存储中的一堆数据,并在循环的每次迭代中创建一个 new GroupBox()
。回到 class 构造函数,每次实例化一个新的 GroupBox 时,我们都会创建 HTML 标签来显示数据并将它们附加到页面。 DOM 操作代码位于 GroupBox
class 方法中,该方法在 class 构造函数中被调用。
还有一件事,每个 GroupBox 都有关联的“主题”,这就是我们有 SubjectBox class 的原因。当用户单击 GroupBox 时,我们会找到关联的 SubjectBox 对象并将它们显示在页面上。
好的,所以这里一切正常,除了我 运行 遇到一个问题。 displayGroupBoxes()
函数获取关联的主题并将它们传递回构造函数以创建数据的 HTML 标记并将其附加到页面。当所有 DOM 操作代码都在构造函数中时,我得到了这个工作。然而,我收到了一位同事的代码审查,他们说最好将 DOM 操作代码分离到 class 方法中以提高可读性,也就是说,这样它就不会全部在构造函数中。执行此操作后,我将无法再访问从 displayGroupBoxes
函数传递过来的数据。
我知道这里有很多非常特定于项目的代码,但我希望通过这种解释,有人可以查看代码并理解为什么我无法访问 displayGroupBoxes
来自 GroupBox class 方法的函数 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
函数传递给 class 方法,该方法创建 HTML 标签数据并将其附加到页面。当我将所有 DOM 操作代码都放在 class 构造函数中时,这起作用了,但是当我将它移到构造函数之外到它自己的 class 方法以提高可读性时,除了这些属性之外,一切都有效通过了。我一定是说错了,但我不明白这个问题。
问题出在 GroupBox
构造函数中,它仅定义名称、类型和徽标。您需要在 class 定义中添加您的其他属性才能使用它们。
constructor(groupOptions) {
super({
name: groupOptions.name,
type: groupOptions.type,
logo: groupOptions.logo,
container: groupOptions.container,
subjects: groupOptions.subjects,
subjectIcons: groupOptions.subjectIcons || [],
headers: groupOptions.headers
});
根据我收到的回复在此分享答案。我标记为正确的答案几乎是正确的,除了不应在 super()
调用中传递属性。我需要在 class 构造函数中定义属性,以便稍后能够从 displayGroupFunctions
向它们传递数据。
现在正如@Bergi 提到的,我仍然需要从 构造函数 外部调用 class 方法 createGroupBox
,但以下代码解决了我原来的问题问题:
class GroupBox extends Box {
// PARAM: groupOptions = {}
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;
-----> new code:
this.container = groupOptions.container;
this.subjects = groupOptions.subjects;
this.subjectIcons = groupOptions.subjectIcons;
this.headers = groupOptions.headers;
----> this should be called from outside the constructor
// Create HTML Elements and Append To Page
this.createGroupBox();
}