skip to Main Content

I want to log, and modify the values assigned at the innerHTML attribute of all dynamically loaded scripts-tags in the page.

To do this, I have come up with the following code:

Object.defineProperty(HTMLScriptElement.prototype, "innerHTML", {
    set: function (value) {
        console.log(value + 1)
    }
});

When loaded into the page the following instructions:

o = document.createElement('script');
o.innerHTML = 1;

will print ‘2’, therefore, I can ‘intercept’ and modify the assignments successfully.

However, I don’t know to save the result into the original innerHTML variable defined in the parent prototype: HTMLElement so that the body of the script will actually contain show 2 when inspected through the DOM.

I have tried:

Object.defineProperty(HTMLScriptElement.prototype, "innerHTML", {
    set: function (value) {
        HTMLElement.prototype.innerHTML = value +1;
    }
});

But this results in an "illegal invocation" error.

While this:

Object.defineProperty(HTMLScriptElement.prototype, "innerHTML", {
    set: function (value) {
        HTMLScriptElement.prototype.innerHTML = value +1;
    }
});

results in: "Maximum call stack size exceeded".

How can I assign the modified value to the innerHTML attribute of the parent prototype?

2

Answers


  1. Chosen as BEST ANSWER

    Nevermind, I have found a solution:

    const originalInnerHTMLDescriptor = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML');
    
    // Step 2: Define custom setter.
    Object.defineProperty(HTMLScriptElement.prototype, 'innerHTML', {
        // Define the setter
        set: function(value) {
            const modifiedValue = value + 1;
    
            // Call the original setter.
            originalInnerHTMLDescriptor.set.call(this, modifiedValue);
        },
    
        get: function() {
            return originalInnerHTMLDescriptor.get.call(this);
        }
    });
    

  2. There are 2 problems here,
    innerHTML setter and getter belongs to Element.prototype
    HTMLScriptElement.prototype inherits those accessors but does not own them.

    The approach you tried to still keep the innerHTML functionality
    does not work because you are changing the prototype of the class
    instead of changing the instance innerHTML.

    To do that, you need first to save the original innerHTML setter function

    const innerHTMLSetter = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML').set
    
    Object.defineProperty(Element.prototype, 'innerHTML', {
      set(value) {
        if (this instanceof HTMLScriptElement) {
          console.log(value + 1)
          innerHTMLSetter.call(this, value + 1)
          return
        }
    
       innerHTMLSetter.call(this, value)
      }
    })
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search