代码之家  ›  专栏  ›  技术社区  ›  Mickey Vershbow

Javascript,如何将属性从方法传递到类构造函数?

  •  0
  • Mickey Vershbow  · 技术社区  · 4 年前

    我正在开发一个普通的JS/jQuery应用程序,它从会话存储中获取数据并在浏览器中显示。我创建了一个“Box”类,它表示浏览器页面上的一个Box(即html卡)。构造函数具有各种属性,如 name: this.name

    有两种不同类型的框——Group和Subject——所以我创建了两个子类 class GroupBox extends Box class SubjectBox extends Box .

    它的工作原理如下:在初始页面加载时,我们调用一个函数 displayGroupBoxes new GroupBox() 在循环的每次迭代中。在类构造函数中备份,每次实例化一个新的GroupBox时,我们都会创建HTML标记来显示数据并将它们附加到页面中。DOM操作代码位于 GroupBox

    还有一件事,每个GroupBox都有相关的“主题”,这就是为什么我们有SubjectBox类。当用户单击GroupBox时,我们会找到相关的SubjectBox对象并将其显示在页面上。

    好的,这里一切正常,除了我遇到一个问题。这个 displayGroupBoxes() 函数获取关联的主题并将其传递回构造函数,以便为数据创建HTML标记并将其附加到页面。当所有DOM操作代码都在构造函数中时,我实现了这一点。然而,我收到一位同事的代码审查,他们说最好将DOM操作代码分离到一个类方法中,以提高可读性,也就是说,它不完全在构造函数中。一旦我这样做了,我就再也无法访问从 作用

    显示组框 来自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);
      }
    }
    
    
    

    DisplayGroupBox()

    // --------- 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 显示组框 函数调用类方法,该类方法为数据创建HTML标记并将其附加到页面。当我将所有DOM操作代码都放在类构造函数中时,这种方法就起作用了,但当我将其移到构造函数外部以使其具有可读性时,除了这些属性被传递之外,其他一切都起作用了。我一定是打错电话了,但我不明白这个问题。

    1 回复  |  直到 4 年前
        1
  •  0
  •   GenericUser    4 年前

    问题出在 GroupBox

      constructor(groupOptions) {
        super({
          name: groupOptions.name,
          type: groupOptions.type,
          logo: groupOptions.logo,
          container: groupOptions.container,
          subjects: groupOptions.subjects,
          subjectIcons: groupOptions.subjectIcons || [],
          headers: groupOptions.headers
        });
    
        2
  •  0
  •   Mickey Vershbow    4 年前

    根据我得到的回答在这里分享答案。我标记为正确的答案几乎是正确的,除了属性不应该在 super() 呼叫我需要在类构造函数中定义属性,以便能够从 displayGroupFunctions 过后

    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();
      }