While I haven't conducted any performance tests on this technique, it definitely serves as a valuable shield for your array.
(function(undefined) {
var protectedArrays = [];
protectArray = function guardArray(arr) {
protectedArrays.push(arr);
return getPrivateUpdater(arr);
}
var isProtected = function(arr) {
return protectedArrays.indexOf(arr)>-1;
}
var getPrivateUpdater = function(arr) {
var ret = {};
Object.keys(funcBackups).forEach(function(funcName) {
ret[funcName] = funcBackups[funcName].bind(arr);
});
return ret;
}
var returnsNewArray = ['Array.prototype.splice'];
var returnsOriginalArray = ['Array.prototype.fill','Array.prototype.reverse','Array.prototype.copyWithin','Array.prototype.sort'];
var returnsLength = ['Array.prototype.push','Array.prototype.unshift'];
var returnsValue = ['Array.prototype.shift','Array.prototype.pop'];
var funcBackups = {};
overwriteFuncs(returnsNewArray, function() { return []; });
overwriteFuncs(returnsOriginalArray, function() { return this; });
overwriteFuncs(returnsLength, function() { return this.length; });
overwriteFuncs(returnsValue, function() { return undefined; });
function overwriteFuncs(funcs, ret) {
for(var i=0,c=funcs.length;i<c;i++)
{
var func = funcs[i];
var funcParts = func.split('.');
var obj = window;
for(var j=0,l=funcParts.length;j<l;j++)
{
(function() {
var part = funcParts[j];
if(j!=l-1) obj = obj[part];
else if(typeof obj[part] === "function")
{
var funcBk = obj[part];
funcBackups[funcBk.name] = funcBk;
obj[part] = renameFunction(funcBk.name, function() {
if(isProtected(this)) return ret.apply(this, arguments);
else return funcBk.apply(this,arguments);
});
}
})();
}
}
}
function renameFunction(name, fn) {
return (new Function("return function (call) { return function " + name +
" () { return call(this, arguments) }; };")())(Function.apply.bind(fn));
};
})();
To utilize this safeguard, follow these steps:
var myArr = [];
var myArrInterface = protectArray(myArr);
myArr.push(5); //This won't work, but returns length as expected
myArrInterface.push(5); //Works as usual
By employing this method, you can maintain an internal copy of the interface that isn't exposed globally, allowing your helper functions to modify the array without any issue. Attempts to use methods such as .push
and .splice
will be thwarted either directly or through using the .bind(myArr,arg)
approach.
While not foolproof, this protector offers solid defense. Another potential strategy involves utilizing the Object.defineProperty
method to create protected properties for the initial 900 indexes. However, there are considerations regarding its implications. Additionally, there's the option of using Object.preventExtensions()
, although reversing its effects when necessary remains a challenge.