| "use strict" |
| // Helpers. |
| function makeAccessorProp(obj, propName, initialValue, hiddenName) { |
| if (!hiddenName) |
| hiddenName = propName + '_'; |
| if (initialValue) |
| Object.defineProperty(obj, hiddenName, { value: initialValue, writable: true, enumerable: false }); |
| Object.defineProperty(obj, propName, |
| { configurable: true, |
| enumerable: true, |
| get: function() { return this[hiddenName]; }, |
| set: function(x) { |
| Object.defineProperty(this, hiddenName, { value: x, writable: true, enumerable: false }); |
| } |
| }); |
| } |
| |
| // Set up a prototype with 4 properties. |
| var proto = {valueProp: 11, valuePropShadowed: 22}; |
| makeAccessorProp(proto, 'accessorProp', 33); |
| makeAccessorProp(proto, 'accessorPropShadowed', 44); |
| |
| // Set up a proxy that uses |proto| as a prototype. |
| var proxyTarget = {valuePropShadowed: 21}; |
| makeAccessorProp(proxyTarget, 'accessorPropShadowed', -44, 'accessorPropShadowed__'); |
| var proxy = wrapWithProto(proxyTarget, proto); |
| |
| // Value getters. |
| assertEq(proxy.valueProp, 11); |
| assertEq(proxy.valuePropShadowed, 21); |
| // Iteration, enumeration, etc. |
| var propNames = []; |
| for (var i in proxy) |
| propNames.push(i); |
| assertEq(propNames.length, 4); |
| assertEq('valueProp' in proxy, true); |
| assertEq(proxy.hasOwnProperty('valueProp'), false); |
| assertEq(Object.getOwnPropertyNames(proxy).indexOf('valueProp'), -1); |
| assertEq('valuePropShadowed' in proxy, true); |
| assertEq(Object.getOwnPropertyNames(proxy).indexOf('valuePropShadowed') == -1, false); |
| assertEq(proxy.hasOwnProperty('valuePropShadowed'), true); |
| // Value setters. |
| proxy.valuePropShadowed = 20; |
| proxy.valueProp = 10; |
| assertEq(proxyTarget.valuePropShadowed, 20); |
| assertEq(proxyTarget.valueProp, 10); |
| // Accessor getters. |
| assertEq(proxy.accessorProp, 33); |
| assertEq(proxy.accessorPropShadowed, -44); |
| // Accessor setters. |
| proxy.accessorProp = 32; |
| proxy.accessorPropShadowed = -43; |
| assertEq(proxy.accessorProp, 32); |
| assertEq(proxy.accessorPropShadowed, -43); |
| // Make sure the underlying objects look right. |
| assertEq(proto.accessorProp_, 33); |
| assertEq(proto.accessorPropShadowed_, 44); |
| assertEq(proto.hasOwnProperty('accessorPropShadowed__'), false); |
| assertEq(proxyTarget.accessorProp_, 32); |
| assertEq(proxyTarget.hasOwnProperty('accessorPropShadowed_'), false); |
| assertEq(proxyTarget.accessorPropShadowed__, -43); |
| |
| // Now, create a new object prototyped to |proxy| and make sure |proxy| behaves |
| // well on the prototype chain. |
| function Constructor() { |
| this.foo = 2; |
| } |
| Constructor.prototype = proxy; |
| var child = new Constructor(); |
| assertEq(child.valueProp, 10); |
| assertEq(child.valuePropShadowed, 20); |
| var childPropNames = []; |
| for (var i in child) |
| childPropNames.push(i); |
| assertEq(childPropNames.length, 5); |
| child.accessorProp = 5; |
| child.accessorPropShadowed = 6; |
| assertEq(child.accessorProp, 5); |
| assertEq(child.accessorPropShadowed, 6); |
| assertEq(child.accessorProp_, 5); |
| assertEq(child.accessorPropShadowed__, 6); |