简体   繁体   English

JavaScript:防止Array.push()

[英]JavaScript: Prevent Array.push()

I have a sealed object with an array member on which I want to prevent direct pushes. 我有一个密封的对象,上面有一个数组成员,我想在该数组成员上防止直接推动。

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

How can I prevent the push? 我如何防止这种推动?

UPDATE: 更新:

Thanks for all the thoughts. 感谢您的所有想法。 I eventually need the JSON to send to the server. 我最终需要JSON才能发送到服务器。 It looks like I might need to use an object for the array then figure out a way to generate and return the JSON needed, or change _something to use .slice(). 看来我可能需要为该数组使用一个对象,然后找出一种生成和返回所需JSON的方法,或者更改_something以使用.slice()。 Will play and report. 将播放并报告。

you could override the push method: 您可以覆盖push方法:

var _d = [];
_d.__proto__.push = function() { return this.length; }

and when you need to use it in your module, call Array.prototype.push : 当您需要在模块中使用它时,请调用Array.prototype.push

_b.addD = function (newD) {
    Array.prototype.push.call(_d, newD);
};

I haven't done any performance tests on this, but this certainly helps to protect your array. 我尚未对此进行任何性能测试,但这无疑有助于保护您的阵列。

(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));
    };
})();

You would use it like so: 您可以这样使用它:

var myArr = [];
var myArrInterface = protectArray(myArr);
myArr.push(5); //Doesn't work, but returns length as expected
myArrInterface.push(5); //Works as normal

This way, you can internally keep a copy of the interface that isn't made global to allow your helper funcs to modify the array as normal, but any attempt to use .push .splice etc will fail, either directly, or using the .bind(myArr,arg) method. 这样,您可以在内部保留一个不全局的接口副本,以允许您的助手.splice正常地修改数组,但是使用.push .splice等的任何尝试都将直接或使用.bind(myArr,arg)失败.bind(myArr,arg)方法。

It's still not completely watertight, but a pretty good protector. 它仍然不是完全防水,而是一个很好的保护器。 You could potentially use the Object.defineProperty method to generate protected properties for the first 900 indexes, but I'm not sure of the implications of this. 您可能会使用Object.defineProperty方法来为前900个索引生成受保护的属性,但是我不确定这样做的含义。 There is also the method Object.preventExtensions() but I'm unaware of a way to undo this effect when you need to change it yourself 也有Object.preventExtensions()方法,但是当您需要自己更改效果时,我不知道有一种方法可以撤消该效果

Thank you, dandavis ! 谢谢你, 丹达维斯

I used the slice method: 我用了slice方法:

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.slice(); } // UPDATED
        });
        _b.updateC = function (newValue) {
            _c = newValue;
        };
        _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({}); // no more update = happiness

This allows me to protect from direct push calls enforcing some logic. 这使我可以防止执行某些逻辑的直接调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM