我有一个带有数组成员的密封对象,我想要阻止直接推送。
var myModule = (function () {
"use strict";
var a = (function () {
var _b = {},
_c = _c = "",
_d = [];
Object.defineProperty(_b, "c", {
get: function () { return _c; }
});
Object.defineProperty(_b, "d", {
get { return _d; }
});
_b.addD = function (newD) {
_d.push(newD);
};
Object.seal(_b);
return _b;
}());
var _something = { B: _b };
return {
Something: _something,
AddD: _b.addD
};
}());
myModule.Something.c = "blah"; // doesn't update = WIN!!
myModule.AddD({}); // pushed = WIN!
myModule.Something.d.push({}); // pushed = sadness
如何阻止推送?
更新
感谢所有的想法。我最终需要将JSON发送到服务器。看起来我可能需要为数组使用一个对象,然后找出生成并返回所需JSON的方法,或者更改 _something 以使用.slice()。将播放和报道。
答案 0 :(得分:2)
你可以覆盖推送方法:
var _d = [];
_d.__proto__.push = function() { return this.length; }
当您需要在模块中使用它时,请致电Array.prototype.push
:
_b.addD = function (newD) {
Array.prototype.push.call(_d, newD);
};
答案 1 :(得分:1)
我还没有对此进行任何性能测试,但这肯定有助于保护您的阵列。
(function(undefined) {
var protectedArrays = [];
protectArray = function protectArray(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));
};
})();
你会像这样使用它:
var myArr = [];
var myArrInterface = protectArray(myArr);
myArr.push(5); //Doesn't work, but returns length as expected
myArrInterface.push(5); //Works as normal
通过这种方式,您可以在内部保留一个不是全局的接口副本,以允许助手func正常修改数组,但是尝试使用.push
.splice
等将直接失败,或使用.bind(myArr,arg)
方法失败。
它仍然不是完全无懈可击,但却是一个非常好的保护者。您可以使用Object.defineProperty
方法为前900个索引生成受保护的属性,但我不确定其含义。还有方法Object.preventExtensions()
,但我不知道在你需要自己改变时撤消这种效果的方法