function isIndex(n) { // This isn't right, but pretend that this checks if n is an index in the // way that SpiderMonkey checks in js_IdIsIndex. return Number(n) % 1 == 0; } function indices(obj) { var result = []; for (var i = 0; i < obj.length; i++) result.push(i); return result; } function paMaker(backing) { return { defineProperty: function(name, desc) { throw new Error("immutable"); }, delete: function(name) { throw new Error("immutable"); }, getOwnPropertyDescriptor: function(name) { if (isIndex(name)) { if (({}).hasOwnProperty.call(backing, name)) return { enumerable: true, configurable: false, writable: false, value: backing[name] }; // report out-of-range indices as not there return undefined; } return Object.getOwnPropertyDescriptor(backing, name); // or something like that }, hasOwn: function(name) { return name in backing; }, has: function(name) { // the "in" test for indexed properties ignores the prototype hierarchy if (isIndex(name)) return name in backing; return name in backing || name in proto; }, get: function(receiver, name) { if (isIndex(name)) { if (({}).hasOwnProperty.call(backing, name)) return backing[name]; return undefined; } return backing[name]; }, set: function(receiver, name, val) { throw new Error("immutable"); }, enumerate: function() { return indices(obj); }, keys: function() { return indices(obj); } }; } Array.prototype[0] = "foo"; Array.prototype[42] = "foo"; var proxy = Proxy.create(paMaker([,2]));