General question: When a default Javascript prototype like Array has been modified, hacked, changed and twisted to the point of being unusable, is there any way to create instances of (or re-implement) the original, un-modified prototype?
My case: I've got some code that is failing in the 'edit' mode of a (horrible, proprietary, closed source...) content management system, because the javascript for the interface of the 'edit' mode of the content management system hacks the absolute living hell out of the Array
prototype.
My code will work in the non-edit mode of the CMS, but, to get there, it has be tested in the 'edit' mode. It's possible to test if a prototype has been modified. Is it possible to re-implement the default Array prototype so I could do something like this:
var hasArrayBeenTrashed = // boolean based on https://stackoverflow.com/questions/574584/
var normalArray.prototype = // based on answer to this question
var myArray = !hasArrayBeenTrashed ? [] : new normalArray;
Example 2: Empty Array Using splice() In the above program, the splice() method is used to remove all the elements of an array. In the splice() method, The first argument is the index of an array to start removing an item from.
Array.prototype.unshift() The unshift() method adds one or more elements to the beginning of an array and returns the new length of the array.
JavaScript shift() removes an element at a specified position and shifts the remaining elements up. The JavaScript unshift() function does the opposite. unshift() adds a new element at a particular position and shifts the remaining elements down the list.
The reduce() method executes a user-supplied "reducer" callback function on each element of the array, in order, passing in the return value from the calculation on the preceding element. The final result of running the reducer across all elements of the array is a single value.
The Array.prototype property represents the prototype for the Array constructor. Array instances inherit from Array.prototype. As with all constructors, you can change the constructor's prototype object to make changes to all Array instances.
Definition and Usage. The prototype constructor allows you to add new properties and methods to the Array() object. When constructing a property, ALL arrays will be given the property, and its value, as default.
prototype is a property available with all JavaScript objects. You are not advised to change the prototype of an object that you do not control. Only change the prototype of your own objects.
As with all constructors, you can change the constructor's prototype object to make changes to all Array instances. Little known fact: Array.prototype itself is an Array:
OP's probably already figured something out by now, but for anyone else coming in from a Google search or wherever, here's a function that returns the unmodified version of any default constructor passed to it:
// Note: the double name assignment below is intentional.
// Only change this part if you want to use a different variable name.
// │││││ The other one here needs to stay the same for internal reference.
// ↓↓↓↓↓ ↓↓↓↓↓
var reset = function reset(constructor) {
if (!(constructor.name in reset)) {
var iframe = document.createElement('iframe');
iframe.src = 'about:blank';
document.body.appendChild(iframe);
reset[constructor.name] = iframe.contentWindow[constructor.name];
document.body.removeChild(iframe);
} return reset[constructor.name];
}
The Problem
Somebody does something stupid to a default prototype...
Array.prototype.push = function () {
var that = this;
[].forEach.call(arguments, function (argument) {
that.splice(Math.round(Math.random()*that.length), 0, argument)
}); return 'Trolololo';
}
...and your code becomes a broken mess.
var myArray = new Array(0, 1, 2, 3);
//-> undefined
// Ok, I made an array.
myArray;
//-> [0, 1, 2, 3]
// So far so good...
myArray.push(4, 5);
//-> "Trolololo"
// What?
myArray;
//-> [5, 0, 1, 2, 4, 3]
// WHAT!?
The Solution
So you throw that function into the mix...
var reset = function reset(constructor) {
if (!(constructor.name in reset)) {
var iframe = document.createElement('iframe');
iframe.src = 'about:blank';
document.body.appendChild(iframe);
reset[constructor.name] = iframe.contentWindow[constructor.name];
document.body.removeChild(iframe);
} return reset[constructor.name];
}
...and put it to use like so.
var myArray = new reset(Array)(0, 1, 2, 3);
//-> undefined
// Looks the same
myArray;
//-> [0, 1, 2, 3]
// Still looks the same
myArray.push(4, 5);
//-> 6
// Hey, it returned what it's supposed to...
myArray;
//-> [0, 1, 2, 3, 4, 5]
// ...and all's right with the world again!
Also, because each reset constructor is cached the first time it's returned, you can save a character if you want to by referencing the cache directly (reset.Array
) instead of through the function (reset(Array)
) every time after that.
Good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With