function assert(b) { if (!b) throw new Error("bad assertion!"); } function test(f) { for (let i = 0; i < 1000; i++) f(); } function shallowCopy(arr) { let result = []; for (let item of arr) result.push(item); return result; } function shallowEqual(a, b) { if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) return false; } return true; } test(function() { let target = [10, 20, 30, 40]; let copy = shallowCopy(target); let handler = { }; let proxy = new Proxy(target, handler); proxy.reverse(); copy.reverse(); assert(shallowEqual(proxy, target)); assert(shallowEqual(target, copy)); }); test(function() { let target = [10, 20, 30, 40]; let copy = shallowCopy(target); let getSet = new Set; let hasSet = new Set; let handler = { get(theTarget, key) { getSet.add(key); return theTarget[key]; }, has(theTarget, key) { hasSet.add(key); return Reflect.has(theTarget, key); } }; let proxy = new Proxy(target, handler); proxy.reverse(); copy.reverse(); assert(shallowEqual(proxy, target)); assert(shallowEqual(target, copy)); assert(getSet.has("0")); assert(getSet.has("1")); assert(getSet.has("2")); assert(getSet.has("3")); assert(getSet.has("length")); assert(hasSet.has("0")); assert(hasSet.has("1")); assert(hasSet.has("2")); assert(hasSet.has("3")); }); test(function() { let target = [10, 20, 30, 40]; let getSet = new Set; let hasSet = new Set; let deleteSet = new Set; let handler = { get(theTarget, key) { getSet.add(key); return theTarget[key]; }, has(theTarget, key) { hasSet.add(key); if (key === "0" || key === "1") return true; assert(key === "2" || key === "3"); return false; }, deleteProperty(theTarget, key) { deleteSet.add(key); return Reflect.deleteProperty(theTarget, key); } }; let proxy = new Proxy(target, handler); proxy.reverse(); assert(shallowEqual(proxy, target)); assert(getSet.has("0")); assert(getSet.has("1")); assert(getSet.has("2")); assert(getSet.has("3")); assert(getSet.has("length")); assert(getSet.has("reverse")); assert(getSet.size === 6); assert(hasSet.has("0")); assert(hasSet.has("1")); assert(hasSet.has("2")); assert(hasSet.has("3")); assert(hasSet.size === 4); assert(deleteSet.has("0")); assert(deleteSet.has("1")); assert(!deleteSet.has("2")); assert(!deleteSet.has("3")); }); test(function() { let target = [10, 20, 30, 40]; let error; let handler = { has(theTarget, key) { return false; }, deleteProperty(theTarget, key) { if (key === "0") { error = new Error; throw error; } return true; } }; let proxy = new Proxy(target, handler); let threw = false; try { proxy.reverse(); } catch(e) { threw = true; assert(e === error); } assert(threw); }); test(function() { let target = [10, 20, 30, 40]; let error; let handler = { has(theTarget, key) { if (key === "0") { error = new Error; throw error; } return false; } }; let proxy = new Proxy(target, handler); let threw = false; try { proxy.reverse(); } catch(e) { threw = true; assert(e === error); } assert(threw); }); test(function() { let target = [10, 20, 30, 40]; let error; let handler = { has(theTarget, key) { if (key === "3") { error = new Error; throw error; } return false; } }; let proxy = new Proxy(target, handler); let threw = false; try { proxy.reverse(); } catch(e) { threw = true; assert(e === error); } assert(threw); }); test(function() { let target = [10, 20, 30, 40]; let error; let getSet = new Set; let handler = { get(theTarget, key) { getSet.add(key); return theTarget[key]; }, has(theTarget, key) { return false; }, deleteProperty() { return true; } }; let proxy = new Proxy(target, handler); proxy.reverse(); assert(!getSet.has("0")); assert(!getSet.has("1")); assert(!getSet.has("2")); assert(!getSet.has("3")); assert(getSet.size === 2); assert(getSet.has("reverse")); assert(getSet.has("length")); });