1

I'd like to assign a Javascript Class instance to an HTML element using this method: https://stackoverflow.com/a/1402782/13107219

This allows me to access the class instance later using the following (which is good)

var class_instance = document.getElementById('my_element').my_class;

However, I'd also like to be able to access the HTML element from within the Javascript class instance

var class_instance=new MY_CLASS(); // class constructor creates corresponding HTML element and stores it in property 'html_element'

class_instance.html_element.innerHTML='I can access and update the HTML easily';

So, ideally, I'd like to be able to have the following 2 lines in the class constructor:

this.html_element=this.create_html_element(); // create the html element for the box
this.html_element.my_obj=this; // reference this class instance with the HTML element

Questions:
Is my proposed technique going to create a circular reference, memory leak, or cause issues?

Is there a better technique (no JQuery, please) to set it up so I can: 1. Access the class instance having only the HTML element ID and 2. Access the HTML element having only the class instance available?

Full Example

var BOX = class { //class to make a box
        
            constructor(my_prop, color) { // initialize the JS Object
                this.my_prop=my_prop; // define a property
                this.color=color;

                /* ******  My Question:  Are the following 2 lines OK to use? ****** */ 
                this.html_element=this.create_html_element(); // create the html element for the box
                this.html_element.my_obj=this;
  
            }

            create_html_element() { //generate the HTML for the box element and append it to the body
  
                var ele=document.createElement('DIV'); // create html element
                ele.style.border='1px solid #'+this.color; ele.className='box';// style the element border
                document.body.appendChild(ele); // put the element on the screen

                ele.onclick=this._onclick;  //make something happen when the box element is clicked

                return ele; // return the element so we can use 'this.html_element' to reference this element later
            }


            _onclick() { //Do this when the box is clicked
                /* 
                   Note: 'this' here refers to the event.target HTML element (not the JS object)
                   Could use bind to bind to the javascript object instead, but find it more intuitive to have the _onclick reference the html element that was clicked

                   Reference: https://stackoverflow.com/questions/41591250/html-element-attached-to-js-object
                */

                 console.log(this.my_obj.my_prop);
             }

         }


         function makeBoxes(){
             var box1=new BOX('Box 1','c00');
             var box2=new BOX('Box 2','0c0');
             var box3=new BOX('Box 3','00c');

             /* ****** I'd like to be able to use the lines below ****** */
             box1.html_element.innerHTML='Box 1';
             box1.my_prop="I've changed!";


             /* ******* Is it a problem that the following code can be used to access the same element?  Obviously, I wouldn't do the following line, but I didn't know if even being able to use it indicates a circular reference that might cause bloat, memory leaks, any other potential issues? ****** */
             var same_element = box1.html_element.my_obj.html_element.my_obj.html_element.my_obj.html_element;       

         }
.box{
width:15vw;
height:20vh;
margin:2vh;
display:inline-block;
vertical-align:middle;
}

.btn{
display:block;
}
<html>
  <body>
      <div class='btn' onclick='makeBoxes();'>Click to Make Boxes</div>
  </body>
</html>
phprox
  • 13
  • 3

1 Answers1

0

Circular references are not bad in themselves. In particular, V8's garbage collection doesn't use reference counting (like, say, CPython), so if you're using JavaScript as implemented by V8, then circular references won't prevent garbage collection. There are some gotchas, though.

But circular references are only about the removability of objects. If you are destroying an element, you could remove all the references, which will definitely let them safely get garbage collected.

If you want to avoid expando properties, you could use a JavaScript Map to map from HTML elements to class instances. For example:

// Global context:
const domToInstance = new Map();
//...
// In constructor:
  this.html_element=this.create_html_element(); // create the html element for the box
  domToInstance.set(this.html_element, this); // reference this class instance with the HTML element
edemaine
  • 2,699
  • 11
  • 20