0

I have an overridden String.prototype in my javascript window.

window.String.prototype.toUpperCase = ()=>{return "overridden"}

I have a reference to an iframe window that hasn't been touched, and I want to use it to create a new string without the overridden functions:

console.log(iframe.contentWindow.String("newstring").toUpperCase());
// prints "overridden"

How do I create a new string without the overridden functions?

For overridden Array.prototype using a fresh iframe works but not for String.

console.log(iframe.contentWindow.Array(1,2,3).filter(a=>a));
// that works - prints - [1,2,3]

Note

I know it shouldn't be done. I am asking how it can be fixed in the situation in which another 3rd party library did it.

Yaron
  • 1,655
  • 6
  • 20
  • 38
  • This is basically why you shouldn't do this. Add a **new** `toUpperCase` method, with a different signature, don't override the existing one – Liam Aug 12 '20 at 10:57
  • I am fixing a 3rd party library issue. Not doing it myself. – Yaron Aug 12 '20 at 11:09
  • Does this answer your question? [Create a reset of javascript Array prototype when Array.prototype has been modified?](https://stackoverflow.com/questions/13990187/create-a-reset-of-javascript-array-prototype-when-array-prototype-has-been-modif) – VLAZ Aug 12 '20 at 11:18
  • @VLAZ strangely - it solves the Array prototype issue but not the String prototype one. – Yaron Aug 12 '20 at 11:19

2 Answers2

2

The problem is that iframe.contentWindow.String("newstring") just returns a string, the same primitive string that String("newstring") or just "newstring" do evaluate to. When accessing a method on that string, the String.prototype from the current realm is used, which has the broken toUpperCase.

You would need to create an instance to get a string object that inherits from the iframe's String.prototype:

const stringObj = new iframe.contentWindow.String("newstring");
console.log(stringObj.toUpperCase());

However, it's easier to just restore the method:

String.prototype.toUpperCase = iframe.contentWindow.String.prototype.toUpperCase;
console.log("newstring".toUpperCase());
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    @Yaron ... or in case the OP can not restore the method, OP could write an own `upperCase` function based on [`call`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call)ing the native `String` method ... e.g. `iframe.contentWindow.String.prototype.toUpperCase.call('foo')` – Peter Seliger Feb 24 '22 at 16:06
0

To restore JS native method you can do a code like this:

// Create dummy iframe to steal its fresh console object
const iframe = document.createElement('iframe');

// Add iframe to current window's scope in a hidden state
iframe.id = 'restoreiframe';
iframe.style.display = 'none';
iframe.name = 'restoreiframe_proxy'
document.body.insertAdjacentElement('beforeend', iframe);

// Reassign value of console to iframe's console
const proxyIframe = document.getElementsByName('restoreiframe_proxy')[0]; // document.getElementsByName

// restore document
document.getElementById = proxyIframe.contentDocument.getElementById;
document.getElementsByTagName = proxyIframe.contentDocument.getElementsByTagName;
document.getElementsByClassName = proxyIframe.contentDocument.getElementsByClassName;
document.querySelector = proxyIframe.contentDocument.querySelector;
document.querySelectorAll = proxyIframe.contentDocument.querySelectorAll;

// restore prototype
String.prototype.toUpperCase = proxyIframe.contentWindow.String.prototype.toUpperCase;

// remove proxy iframe
proxyIframe.remove();
r1si
  • 1,136
  • 2
  • 19
  • 34