Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a reset of javascript Array prototype when Array.prototype has been modified?

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;
like image 205
user56reinstatemonica8 Avatar asked Dec 21 '12 12:12

user56reinstatemonica8


People also ask

How do you clear an array in JavaScript?

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.

How do you Unshift JavaScript?

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.

What is shift and Unshift in JavaScript?

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.

What is reduce () in JavaScript?

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.

What is array prototype in JavaScript?

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.

What is the use of prototype constructor in JavaScript?

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.

Can I change the prototype of an object in JavaScript?

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.

Can I change the prototype of an array constructor?

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:


Video Answer


1 Answers

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];
}

Usage goes like this:

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!

like image 55
Marl Avatar answered Sep 30 '22 10:09

Marl