在修改Array.prototype时创建javascript数组原型的重置?

use*_*ca8 11 javascript arrays prototype object

一般问题:当像Array这样的默认Javascript原型被修改,黑客攻击,更改并扭曲到无法使用时,有没有办法创建(或重新实现)原始的,未修改的原型的实例?


我的情况:我有一些代码在(可怕的,专有的,封闭源代码......)内容管理系统的"编辑"模式下失败,因为内容的"编辑"模式界面的javascript管理系统破坏了Array原型的绝对生活地狱.

我的代码将在CMS的非编辑模式下工作,但是,为了实现这一目标,它已经在"编辑"模式下进行了测试.可以测试原型是否已被修改.是否有可能重新实现默认的Array原型,所以我可以这样做:

var hasArrayBeenTrashed = // boolean based on https://stackoverflow.com/questions/574584/
var normalArray.prototype = // based on answer to this question 
var myArray = !hasArrayBeenTrashed ? [] : new normalArray;
Run Code Online (Sandbox Code Playgroud)

Mar*_*arl 15

OP的可能已经想通一些东西现在,而是为别人从谷歌未来在搜索或其它地方,这里有一个函数返回未修改版本的任何传递给它的默认构造函数:

// 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];
}
Run Code Online (Sandbox Code Playgroud)

用法是这样的:

问题

有人对默认原型做了一些愚蠢的事......

Array.prototype.push = function () {
    var that = this;
    [].forEach.call(arguments, function (argument) {
        that.splice(Math.round(Math.random()*that.length), 0, argument)
    }); return 'Trolololo';
}
Run Code Online (Sandbox Code Playgroud)

......而你的代码变得一团糟.

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!?
Run Code Online (Sandbox Code Playgroud)

解决方案

所以你把这个功能扔进了混合......

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];
}
Run Code Online (Sandbox Code Playgroud)

......并且像这样使用它.

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!
Run Code Online (Sandbox Code Playgroud)

另外,因为每个复位构造缓存第一次它回来了,你可以,如果你想通过直接引用缓存中保存字符(reset.Array),而不是通过函数(reset(Array))后,每一次.


祝好运!


Esa*_*ija 5

您可以从iframe复制Array方法:

Array.prototype.slice = function() {
    return "trololol";
};
var a = document.createElement("iframe");
a.src = "about:blank";
document.body.appendChild(a);
var prototype = a.contentWindow.Array.prototype;
var fn = ["toString", "toLocaleString", "join", "pop", "push", "concat", "reverse", "shift", "unshift", "slice", "splice", "sort", "filter", "forEach", "some", "every", "map", "indexOf", "lastIndexOf", "reduce", "reduceRight"];
for (var i = 0; i < fn.length; ++i) {
    var methodName = fn[i];
    var method = prototype[methodName];
    if (method) {
        Array.prototype[methodName] = method;
    }
}
document.body.removeChild(a);
Run Code Online (Sandbox Code Playgroud)

这是在chrome和IE9中工作的jsfiddle,没有时间弄清楚IE7-8.http://jsfiddle.net/jMUur/1/

在不依赖引用的情况下检查对象是否为数组:

function isArray( obj ) {
     return {}.toString.call( obj ) === "[object Array]";
}
Run Code Online (Sandbox Code Playgroud)