testDirectProxySet10.js (1941B)
1 // Assigning to a non-existing property of a plain object defines that 2 // property on that object, even if a proxy is on the proto chain. 3 4 // Create an object that behaves just like obj except it throws (instead of 5 // returning undefined) if you try to get a property that doesn't exist. 6 function throwIfNoSuchProperty(obj) { 7 return new Proxy(obj, { 8 get(t, id) { 9 if (id in t) 10 return t[id]; 11 throw new Error("no such handler method: " + id); 12 } 13 }); 14 } 15 16 // Use a touchy object as our proxy handler in this test. 17 var hits = 0, savedDesc = undefined; 18 var touchyHandler = throwIfNoSuchProperty({ 19 set: undefined 20 }); 21 var target = {}; 22 var proto = new Proxy(target, touchyHandler); 23 var receiver = Object.create(proto); 24 25 // This assignment `receiver.x = 2` results in a series of [[Set]] calls, 26 // starting with: 27 // 28 // - receiver.[[Set]]() 29 // - receiver is an ordinary object. 30 // - This looks for an own property "x" on receiver. There is none. 31 // - So it walks the prototype chain, doing a tail-call to: 32 // - proto.[[Set]]() 33 // - proto is a proxy. 34 // - This does handler.[[Get]]("set") to look for a set trap 35 // (that's why we need `set: undefined` on the handler, above) 36 // - Since there's no "set" handler, it tail-calls: 37 // - target.[[Set]]() 38 // - ordinary 39 // - no own property "x" 40 // - tail call to: 41 // - Object.prototype.[[Set]]() 42 // - ordinary 43 // - no own property "x" 44 // - We're at the end of the line: there's nothing left on the proto chain. 45 // - So at last we call: 46 // - receiver.[[DefineOwnProperty]]() 47 // - ordinary 48 // - creates the property 49 // 50 // Got all that? Let's try it. 51 // 52 receiver.x = 2; 53 assertEq(receiver.x, 2); 54 55 var desc = Object.getOwnPropertyDescriptor(receiver, "x"); 56 assertEq(desc.enumerable, true); 57 assertEq(desc.configurable, true); 58 assertEq(desc.writable, true); 59 assertEq(desc.value, 2);