Implement Object.prototype.{hasOwnProperty, propertyIsEnumerable} for proxies.
Refactor trap invocation. Test other Object.prototype functionality for proxies. R=ager@chromium.org BUG=v8:1543 TEST= Review URL: http://codereview.chromium.org/7436004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8707 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
5fba76891b
commit
3f5bc11c55
@ -195,6 +195,7 @@ function FormatMessage(message) {
|
||||
non_extensible_proto: ["%0", " is not extensible"],
|
||||
handler_non_object: ["Proxy.", "%0", " called with non-object as handler"],
|
||||
handler_trap_missing: ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
|
||||
handler_trap_must_be_callable: ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"],
|
||||
handler_returned_false: ["Proxy handler ", "%0", " returned false for '", "%1", "' trap"],
|
||||
handler_returned_undefined: ["Proxy handler ", "%0", " returned undefined for '", "%1", "' trap"],
|
||||
proxy_prop_not_configurable: ["Trap ", "%1", " of proxy handler ", "%0", " returned non-configurable descriptor for property ", "%2"],
|
||||
|
@ -136,6 +136,10 @@ function DerivedHasTrap(name) {
|
||||
return !!this.getPropertyDescriptor(name)
|
||||
}
|
||||
|
||||
function DerivedHasOwnTrap(name) {
|
||||
return !!this.getOwnPropertyDescriptor(name)
|
||||
}
|
||||
|
||||
function DerivedKeysTrap() {
|
||||
var names = this.getOwnPropertyNames()
|
||||
var enumerableNames = []
|
||||
|
@ -232,6 +232,10 @@ function ObjectValueOf() {
|
||||
|
||||
// ECMA-262 - 15.2.4.5
|
||||
function ObjectHasOwnProperty(V) {
|
||||
if (%IsJSProxy(this)) {
|
||||
var handler = %GetHandler(this);
|
||||
return CallTrap1(handler, "hasOwn", DerivedHasOwnTrap, TO_STRING_INLINE(V));
|
||||
}
|
||||
return %HasLocalProperty(TO_OBJECT_INLINE(this), TO_STRING_INLINE(V));
|
||||
}
|
||||
|
||||
@ -249,7 +253,12 @@ function ObjectIsPrototypeOf(V) {
|
||||
|
||||
// ECMA-262 - 15.2.4.6
|
||||
function ObjectPropertyIsEnumerable(V) {
|
||||
return %IsPropertyEnumerable(ToObject(this), ToString(V));
|
||||
var P = ToString(V);
|
||||
if (%IsJSProxy(this)) {
|
||||
var desc = GetOwnProperty(this, P);
|
||||
return IS_UNDEFINED(desc) ? false : desc.isEnumerable();
|
||||
}
|
||||
return %IsPropertyEnumerable(ToObject(this), P);
|
||||
}
|
||||
|
||||
|
||||
@ -310,9 +319,7 @@ function ObjectKeys(obj) {
|
||||
throw MakeTypeError("obj_ctor_property_non_object", ["keys"]);
|
||||
if (%IsJSProxy(obj)) {
|
||||
var handler = %GetHandler(obj);
|
||||
var keys = handler.keys;
|
||||
if (IS_UNDEFINED(keys)) keys = DerivedKeysTrap;
|
||||
var names = %_CallFunction(handler, keys);
|
||||
var names = CallTrap0(handler, "keys", DerivedKeysTrap);
|
||||
return ToStringArray(names);
|
||||
}
|
||||
return %LocalKeys(obj);
|
||||
@ -583,16 +590,41 @@ function ConvertDescriptorArrayToDescriptor(desc_array) {
|
||||
}
|
||||
|
||||
|
||||
// For Harmony proxies.
|
||||
function GetTrap(handler, name, defaultTrap) {
|
||||
var trap = handler[name];
|
||||
if (IS_UNDEFINED(trap)) {
|
||||
if (IS_UNDEFINED(defaultTrap)) {
|
||||
throw MakeTypeError("handler_trap_missing", [handler, name]);
|
||||
}
|
||||
trap = defaultTrap;
|
||||
} else if (!IS_FUNCTION(trap)) {
|
||||
throw MakeTypeError("handler_trap_must_be_callable", [handler, name]);
|
||||
}
|
||||
return trap;
|
||||
}
|
||||
|
||||
|
||||
function CallTrap0(handler, name, defaultTrap) {
|
||||
return %_CallFunction(handler, GetTrap(handler, name, defaultTrap));
|
||||
}
|
||||
|
||||
|
||||
function CallTrap1(handler, name, defaultTrap, x) {
|
||||
return %_CallFunction(handler, x, GetTrap(handler, name, defaultTrap));
|
||||
}
|
||||
|
||||
|
||||
function CallTrap2(handler, name, defaultTrap, x, y) {
|
||||
return %_CallFunction(handler, x, y, GetTrap(handler, name, defaultTrap));
|
||||
}
|
||||
|
||||
|
||||
// ES5 section 8.12.2.
|
||||
function GetProperty(obj, p) {
|
||||
if (%IsJSProxy(obj)) {
|
||||
var handler = %GetHandler(obj);
|
||||
var getProperty = handler.getPropertyDescriptor;
|
||||
if (IS_UNDEFINED(getProperty)) {
|
||||
throw MakeTypeError("handler_trap_missing",
|
||||
[handler, "getPropertyDescriptor"]);
|
||||
}
|
||||
var descriptor = %_CallFunction(handler, p, getProperty);
|
||||
var descriptor = CallTrap1(obj, "getPropertyDescriptor", void 0, p);
|
||||
if (IS_UNDEFINED(descriptor)) return descriptor;
|
||||
var desc = ToCompletePropertyDescriptor(descriptor);
|
||||
if (!desc.isConfigurable()) {
|
||||
@ -613,9 +645,7 @@ function GetProperty(obj, p) {
|
||||
function HasProperty(obj, p) {
|
||||
if (%IsJSProxy(obj)) {
|
||||
var handler = %GetHandler(obj);
|
||||
var has = handler.has;
|
||||
if (IS_UNDEFINED(has)) has = DerivedHasTrap;
|
||||
return ToBoolean(%_CallFunction(handler, obj, p, has));
|
||||
return ToBoolean(CallTrap1(handler, "has", DerivedHasTrap, p));
|
||||
}
|
||||
var desc = GetProperty(obj, p);
|
||||
return IS_UNDEFINED(desc) ? false : true;
|
||||
@ -623,15 +653,11 @@ function HasProperty(obj, p) {
|
||||
|
||||
|
||||
// ES5 section 8.12.1.
|
||||
function GetOwnProperty(obj, p) {
|
||||
function GetOwnProperty(obj, v) {
|
||||
var p = ToString(v);
|
||||
if (%IsJSProxy(obj)) {
|
||||
var handler = %GetHandler(obj);
|
||||
var getOwnProperty = handler.getOwnPropertyDescriptor;
|
||||
if (IS_UNDEFINED(getOwnProperty)) {
|
||||
throw MakeTypeError("handler_trap_missing",
|
||||
[handler, "getOwnPropertyDescriptor"]);
|
||||
}
|
||||
var descriptor = %_CallFunction(handler, p, getOwnProperty);
|
||||
var descriptor = CallTrap1(handler, "getOwnPropertyDescriptor", void 0, p);
|
||||
if (IS_UNDEFINED(descriptor)) return descriptor;
|
||||
var desc = ToCompletePropertyDescriptor(descriptor);
|
||||
if (!desc.isConfigurable()) {
|
||||
@ -644,7 +670,7 @@ function GetOwnProperty(obj, p) {
|
||||
// GetOwnProperty returns an array indexed by the constants
|
||||
// defined in macros.py.
|
||||
// If p is not a property on obj undefined is returned.
|
||||
var props = %GetOwnProperty(ToObject(obj), ToString(p));
|
||||
var props = %GetOwnProperty(ToObject(obj), ToString(v));
|
||||
|
||||
// A false value here means that access checks failed.
|
||||
if (props === false) return void 0;
|
||||
@ -656,11 +682,7 @@ function GetOwnProperty(obj, p) {
|
||||
// Harmony proxies.
|
||||
function DefineProxyProperty(obj, p, attributes, should_throw) {
|
||||
var handler = %GetHandler(obj);
|
||||
var defineProperty = handler.defineProperty;
|
||||
if (IS_UNDEFINED(defineProperty)) {
|
||||
throw MakeTypeError("handler_trap_missing", [handler, "defineProperty"]);
|
||||
}
|
||||
var result = %_CallFunction(handler, p, attributes, defineProperty);
|
||||
var result = CallTrap2(handler, "defineProperty", void 0, p, attributes);
|
||||
if (!ToBoolean(result)) {
|
||||
if (should_throw) {
|
||||
throw MakeTypeError("handler_returned_false",
|
||||
@ -889,12 +911,7 @@ function ObjectGetOwnPropertyNames(obj) {
|
||||
// Special handling for proxies.
|
||||
if (%IsJSProxy(obj)) {
|
||||
var handler = %GetHandler(obj);
|
||||
var getOwnPropertyNames = handler.getOwnPropertyNames;
|
||||
if (IS_UNDEFINED(getOwnPropertyNames)) {
|
||||
throw MakeTypeError("handler_trap_missing",
|
||||
[handler, "getOwnPropertyNames"]);
|
||||
}
|
||||
var names = %_CallFunction(handler, getOwnPropertyNames);
|
||||
var names = CallTrap0(handler, "getOwnPropertyNames", void 0);
|
||||
return ToStringArray(names, "getOwnPropertyNames");
|
||||
}
|
||||
|
||||
@ -1024,11 +1041,7 @@ function ObjectDefineProperties(obj, properties) {
|
||||
// Harmony proxies.
|
||||
function ProxyFix(obj) {
|
||||
var handler = %GetHandler(obj);
|
||||
var fix = handler.fix;
|
||||
if (IS_UNDEFINED(fix)) {
|
||||
throw MakeTypeError("handler_trap_missing", [handler, "fix"]);
|
||||
}
|
||||
var props = %_CallFunction(handler, fix);
|
||||
var props = CallTrap0(handler, "fix", void 0);
|
||||
if (IS_UNDEFINED(props)) {
|
||||
throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
|
||||
}
|
||||
|
@ -42,22 +42,27 @@ function TestGet(handler) {
|
||||
TestGet({
|
||||
get: function(r, k) { return 42 }
|
||||
})
|
||||
|
||||
TestGet({
|
||||
get: function(r, k) { return this.get2(r, k) },
|
||||
get2: function(r, k) { return 42 }
|
||||
})
|
||||
|
||||
TestGet({
|
||||
getPropertyDescriptor: function(k) { return {value: 42} }
|
||||
})
|
||||
|
||||
TestGet({
|
||||
getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
|
||||
getPropertyDescriptor2: function(k) { return {value: 42} }
|
||||
})
|
||||
|
||||
TestGet({
|
||||
getPropertyDescriptor: function(k) {
|
||||
return {get value() { return 42 }}
|
||||
}
|
||||
})
|
||||
|
||||
TestGet({
|
||||
get: undefined,
|
||||
getPropertyDescriptor: function(k) { return {value: 42} }
|
||||
@ -83,32 +88,38 @@ function TestGetCall(handler) {
|
||||
TestGetCall({
|
||||
get: function(r, k) { return function() { return 55 } }
|
||||
})
|
||||
|
||||
TestGetCall({
|
||||
get: function(r, k) { return this.get2(r, k) },
|
||||
get2: function(r, k) { return function() { return 55 } }
|
||||
})
|
||||
|
||||
TestGetCall({
|
||||
getPropertyDescriptor: function(k) {
|
||||
return {value: function() { return 55 }}
|
||||
}
|
||||
})
|
||||
|
||||
TestGetCall({
|
||||
getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
|
||||
getPropertyDescriptor2: function(k) {
|
||||
return {value: function() { return 55 }}
|
||||
}
|
||||
})
|
||||
|
||||
TestGetCall({
|
||||
getPropertyDescriptor: function(k) {
|
||||
return {get value() { return function() { return 55 } }}
|
||||
}
|
||||
})
|
||||
|
||||
TestGetCall({
|
||||
get: undefined,
|
||||
getPropertyDescriptor: function(k) {
|
||||
return {value: function() { return 55 }}
|
||||
}
|
||||
})
|
||||
|
||||
TestGetCall({
|
||||
get: function(r, k) {
|
||||
if (k == "gg") {
|
||||
@ -146,14 +157,17 @@ function TestSet(handler) {
|
||||
TestSet({
|
||||
set: function(r, k, v) { key = k; val = v; return true }
|
||||
})
|
||||
|
||||
TestSet({
|
||||
set: function(r, k, v) { return this.set2(r, k, v) },
|
||||
set2: function(r, k, v) { key = k; val = v; return true }
|
||||
})
|
||||
|
||||
TestSet({
|
||||
getOwnPropertyDescriptor: function(k) { return {writable: true} },
|
||||
defineProperty: function(k, desc) { key = k; val = desc.value }
|
||||
})
|
||||
|
||||
TestSet({
|
||||
getOwnPropertyDescriptor: function(k) {
|
||||
return this.getOwnPropertyDescriptor2(k)
|
||||
@ -162,22 +176,26 @@ TestSet({
|
||||
defineProperty: function(k, desc) { this.defineProperty2(k, desc) },
|
||||
defineProperty2: function(k, desc) { key = k; val = desc.value }
|
||||
})
|
||||
|
||||
TestSet({
|
||||
getOwnPropertyDescriptor: function(k) {
|
||||
return {get writable() { return true }}
|
||||
},
|
||||
defineProperty: function(k, desc) { key = k; val = desc.value }
|
||||
})
|
||||
|
||||
TestSet({
|
||||
getOwnPropertyDescriptor: function(k) {
|
||||
return {set: function(v) { key = k; val = v }}
|
||||
}
|
||||
})
|
||||
|
||||
TestSet({
|
||||
getOwnPropertyDescriptor: function(k) { return null },
|
||||
getPropertyDescriptor: function(k) { return {writable: true} },
|
||||
defineProperty: function(k, desc) { key = k; val = desc.value }
|
||||
})
|
||||
|
||||
TestSet({
|
||||
getOwnPropertyDescriptor: function(k) { return null },
|
||||
getPropertyDescriptor: function(k) {
|
||||
@ -185,12 +203,14 @@ TestSet({
|
||||
},
|
||||
defineProperty: function(k, desc) { key = k; val = desc.value }
|
||||
})
|
||||
|
||||
TestSet({
|
||||
getOwnPropertyDescriptor: function(k) { return null },
|
||||
getPropertyDescriptor: function(k) {
|
||||
return {set: function(v) { key = k; val = v }}
|
||||
}
|
||||
})
|
||||
|
||||
TestSet({
|
||||
getOwnPropertyDescriptor: function(k) { return null },
|
||||
getPropertyDescriptor: function(k) { return null },
|
||||
@ -279,10 +299,12 @@ function TestDefine(handler) {
|
||||
TestDefine({
|
||||
defineProperty: function(k, d) { key = k; desc = d; return true }
|
||||
})
|
||||
|
||||
TestDefine({
|
||||
defineProperty: function(k, d) { return this.defineProperty2(k, d) },
|
||||
defineProperty2: function(k, d) { key = k; desc = d; return true }
|
||||
})
|
||||
|
||||
TestDefine(Proxy.create({
|
||||
get: function(pr, pk) {
|
||||
return function(k, d) { key = k; desc = d; return true }
|
||||
@ -323,10 +345,12 @@ function TestDelete(handler) {
|
||||
TestDelete({
|
||||
'delete': function(k) { key = k; return k < "z" }
|
||||
})
|
||||
|
||||
TestDelete({
|
||||
'delete': function(k) { return this.delete2(k) },
|
||||
delete2: function(k) { key = k; return k < "z" }
|
||||
})
|
||||
|
||||
TestDelete(Proxy.create({
|
||||
get: function(pr, pk) {
|
||||
return function(k) { key = k; return k < "z" }
|
||||
@ -363,6 +387,7 @@ TestDescriptor({
|
||||
defineProperty: function(k, d) { this["__" + k] = d; return true },
|
||||
getOwnPropertyDescriptor: function(k) { return this["__" + k] }
|
||||
})
|
||||
|
||||
TestDescriptor({
|
||||
defineProperty: function(k, d) { this["__" + k] = d; return true },
|
||||
getOwnPropertyDescriptor: function(k) {
|
||||
@ -404,7 +429,7 @@ assertTrue("object" == typeof Proxy.create({}))
|
||||
|
||||
|
||||
|
||||
// Element (in).
|
||||
// Membership test (in).
|
||||
|
||||
var key
|
||||
function TestIn(handler) {
|
||||
@ -442,26 +467,31 @@ function TestIn(handler) {
|
||||
TestIn({
|
||||
has: function(k) { key = k; return k < "z" }
|
||||
})
|
||||
|
||||
TestIn({
|
||||
has: function(k) { return this.has2(k) },
|
||||
has2: function(k) { key = k; return k < "z" }
|
||||
})
|
||||
|
||||
TestIn({
|
||||
getPropertyDescriptor: function(k) {
|
||||
key = k; return k < "z" ? {value: 42} : void 0
|
||||
}
|
||||
})
|
||||
|
||||
TestIn({
|
||||
getPropertyDescriptor: function(k) { return this.getPropertyDescriptor2(k) },
|
||||
getPropertyDescriptor2: function(k) {
|
||||
key = k; return k < "z" ? {value: 42} : void 0
|
||||
}
|
||||
})
|
||||
|
||||
TestIn({
|
||||
getPropertyDescriptor: function(k) {
|
||||
key = k; return k < "z" ? {get value() { return 42 }} : void 0
|
||||
}
|
||||
})
|
||||
|
||||
TestIn({
|
||||
get: undefined,
|
||||
getPropertyDescriptor: function(k) {
|
||||
@ -477,7 +507,65 @@ TestIn(Proxy.create({
|
||||
|
||||
|
||||
|
||||
// Instanceof (instanceof).
|
||||
// Own Properties (Object.prototype.hasOwnProperty).
|
||||
|
||||
var key
|
||||
function TestHasOwn(handler) {
|
||||
var o = Proxy.create(handler)
|
||||
assertTrue(Object.prototype.hasOwnProperty.call(o, "a"))
|
||||
assertEquals("a", key)
|
||||
assertTrue(Object.prototype.hasOwnProperty.call(o, 99))
|
||||
assertEquals("99", key)
|
||||
assertFalse(Object.prototype.hasOwnProperty.call(o, "z"))
|
||||
assertEquals("z", key)
|
||||
}
|
||||
|
||||
TestHasOwn({
|
||||
hasOwn: function(k) { key = k; return k < "z" }
|
||||
})
|
||||
|
||||
TestHasOwn({
|
||||
hasOwn: function(k) { return this.hasOwn2(k) },
|
||||
hasOwn2: function(k) { key = k; return k < "z" }
|
||||
})
|
||||
|
||||
TestHasOwn({
|
||||
getOwnPropertyDescriptor: function(k) {
|
||||
key = k; return k < "z" ? {value: 42} : void 0
|
||||
}
|
||||
})
|
||||
|
||||
TestHasOwn({
|
||||
getOwnPropertyDescriptor: function(k) {
|
||||
return this.getOwnPropertyDescriptor2(k)
|
||||
},
|
||||
getOwnPropertyDescriptor2: function(k) {
|
||||
key = k; return k < "z" ? {value: 42} : void 0
|
||||
}
|
||||
})
|
||||
|
||||
TestHasOwn({
|
||||
getOwnPropertyDescriptor: function(k) {
|
||||
key = k; return k < "z" ? {get value() { return 42 }} : void 0
|
||||
}
|
||||
})
|
||||
|
||||
TestHasOwn({
|
||||
hasOwn: undefined,
|
||||
getOwnPropertyDescriptor: function(k) {
|
||||
key = k; return k < "z" ? {value: 42} : void 0
|
||||
}
|
||||
})
|
||||
|
||||
TestHasOwn(Proxy.create({
|
||||
get: function(pr, pk) {
|
||||
return function(k) { key = k; return k < "z" }
|
||||
}
|
||||
}))
|
||||
|
||||
|
||||
|
||||
// Instanceof (instanceof)
|
||||
|
||||
function TestInstanceof() {
|
||||
var o = {}
|
||||
@ -514,7 +602,7 @@ TestInstanceof()
|
||||
|
||||
|
||||
|
||||
// Prototype (Object.getPrototypeOf).
|
||||
// Prototype (Object.getPrototypeOf, Object.prototype.isPrototypeOf).
|
||||
|
||||
function TestPrototype() {
|
||||
var o = {}
|
||||
@ -528,6 +616,32 @@ function TestPrototype() {
|
||||
assertSame(Object.getPrototypeOf(p2), o)
|
||||
assertSame(Object.getPrototypeOf(p3), p2)
|
||||
assertSame(Object.getPrototypeOf(p4), null)
|
||||
|
||||
assertTrue(Object.prototype.isPrototypeOf(o))
|
||||
assertFalse(Object.prototype.isPrototypeOf(p1))
|
||||
assertTrue(Object.prototype.isPrototypeOf(p2))
|
||||
assertTrue(Object.prototype.isPrototypeOf(p3))
|
||||
assertFalse(Object.prototype.isPrototypeOf(p4))
|
||||
assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, o))
|
||||
assertFalse(Object.prototype.isPrototypeOf.call(Object.prototype, p1))
|
||||
assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p2))
|
||||
assertTrue(Object.prototype.isPrototypeOf.call(Object.prototype, p3))
|
||||
assertFalse(Object.prototype.isPrototypeOf.call(Object.prototype, p4))
|
||||
assertFalse(Object.prototype.isPrototypeOf.call(o, o))
|
||||
assertFalse(Object.prototype.isPrototypeOf.call(o, p1))
|
||||
assertTrue(Object.prototype.isPrototypeOf.call(o, p2))
|
||||
assertTrue(Object.prototype.isPrototypeOf.call(o, p3))
|
||||
assertFalse(Object.prototype.isPrototypeOf.call(o, p4))
|
||||
assertFalse(Object.prototype.isPrototypeOf.call(p1, p1))
|
||||
assertFalse(Object.prototype.isPrototypeOf.call(p1, o))
|
||||
assertFalse(Object.prototype.isPrototypeOf.call(p1, p2))
|
||||
assertFalse(Object.prototype.isPrototypeOf.call(p1, p3))
|
||||
assertFalse(Object.prototype.isPrototypeOf.call(p1, p4))
|
||||
assertFalse(Object.prototype.isPrototypeOf.call(p2, p1))
|
||||
assertFalse(Object.prototype.isPrototypeOf.call(p2, p2))
|
||||
assertTrue(Object.prototype.isPrototypeOf.call(p2, p3))
|
||||
assertFalse(Object.prototype.isPrototypeOf.call(p2, p4))
|
||||
assertFalse(Object.prototype.isPrototypeOf.call(p3, p2))
|
||||
}
|
||||
|
||||
TestPrototype()
|
||||
@ -544,13 +658,16 @@ function TestPropertyNames(names, handler) {
|
||||
TestPropertyNames([], {
|
||||
getOwnPropertyNames: function() { return [] }
|
||||
})
|
||||
|
||||
TestPropertyNames(["a", "zz", " ", "0"], {
|
||||
getOwnPropertyNames: function() { return ["a", "zz", " ", 0] }
|
||||
})
|
||||
|
||||
TestPropertyNames(["throw", "function "], {
|
||||
getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
|
||||
getOwnPropertyNames2: function() { return ["throw", "function "] }
|
||||
})
|
||||
|
||||
TestPropertyNames(["[object Object]"], {
|
||||
get getOwnPropertyNames() {
|
||||
return function() { return [{}] }
|
||||
@ -566,22 +683,27 @@ function TestKeys(names, handler) {
|
||||
TestKeys([], {
|
||||
keys: function() { return [] }
|
||||
})
|
||||
|
||||
TestKeys(["a", "zz", " ", "0"], {
|
||||
keys: function() { return ["a", "zz", " ", 0] }
|
||||
})
|
||||
|
||||
TestKeys(["throw", "function "], {
|
||||
keys: function() { return this.keys2() },
|
||||
keys2: function() { return ["throw", "function "] }
|
||||
})
|
||||
|
||||
TestKeys(["[object Object]"], {
|
||||
get keys() {
|
||||
return function() { return [{}] }
|
||||
}
|
||||
})
|
||||
|
||||
TestKeys(["a", "0"], {
|
||||
getOwnPropertyNames: function() { return ["a", 23, "zz", "", 0] },
|
||||
getOwnPropertyDescriptor: function(k) { return {enumerable: k.length == 1} }
|
||||
})
|
||||
|
||||
TestKeys(["23", "zz", ""], {
|
||||
getOwnPropertyNames: function() { return this.getOwnPropertyNames2() },
|
||||
getOwnPropertyNames2: function() { return ["a", 23, "zz", "", 0] },
|
||||
@ -590,6 +712,7 @@ TestKeys(["23", "zz", ""], {
|
||||
},
|
||||
getOwnPropertyDescriptor2: function(k) { return {enumerable: k.length != 1} }
|
||||
})
|
||||
|
||||
TestKeys(["a", "b", "c", "5"], {
|
||||
get getOwnPropertyNames() {
|
||||
return function() { return ["0", 4, "a", "b", "c", 5] }
|
||||
@ -598,6 +721,7 @@ TestKeys(["a", "b", "c", "5"], {
|
||||
return function(k) { return {enumerable: k >= "44"} }
|
||||
}
|
||||
})
|
||||
|
||||
TestKeys([], {
|
||||
get getOwnPropertyNames() {
|
||||
return function() { return ["a", "b", "c"] }
|
||||
@ -661,6 +785,7 @@ function TestFix(names, handler) {
|
||||
TestFix([], {
|
||||
fix: function() { return {} }
|
||||
})
|
||||
|
||||
TestFix(["a", "b", "c", "d", "zz"], {
|
||||
fix: function() {
|
||||
return {
|
||||
@ -672,12 +797,14 @@ TestFix(["a", "b", "c", "d", "zz"], {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
TestFix(["a"], {
|
||||
fix: function() { return this.fix2() },
|
||||
fix2: function() {
|
||||
return {a: {value: 4, writable: true, configurable: true, enumerable: true}}
|
||||
}
|
||||
})
|
||||
|
||||
TestFix(["b"], {
|
||||
get fix() {
|
||||
return function() {
|
||||
@ -685,3 +812,87 @@ TestFix(["b"], {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
// String conversion (Object.prototype.toString, Object.prototype.toLocaleString)
|
||||
|
||||
var key
|
||||
function TestToString(handler) {
|
||||
var o = Proxy.create(handler)
|
||||
key = ""
|
||||
assertEquals("[object Object]", Object.prototype.toString.call(o))
|
||||
assertEquals("", key)
|
||||
assertEquals("my_proxy", Object.prototype.toLocaleString.call(o))
|
||||
assertEquals("toString", key)
|
||||
}
|
||||
|
||||
TestToString({
|
||||
get: function(r, k) { key = k; return function() { return "my_proxy" } }
|
||||
})
|
||||
|
||||
TestToString({
|
||||
get: function(r, k) { return this.get2(r, k) },
|
||||
get2: function(r, k) { key = k; return function() { return "my_proxy" } }
|
||||
})
|
||||
|
||||
TestToString(Proxy.create({
|
||||
get: function(pr, pk) {
|
||||
return function(r, k) { key = k; return function() { return "my_proxy" } }
|
||||
}
|
||||
}))
|
||||
|
||||
|
||||
|
||||
// Value conversion (Object.prototype.toValue)
|
||||
|
||||
function TestValueOf(handler) {
|
||||
var o = Proxy.create(handler)
|
||||
assertSame(o, Object.prototype.valueOf.call(o))
|
||||
}
|
||||
|
||||
TestValueOf({})
|
||||
|
||||
|
||||
|
||||
// Enumerability (Object.prototype.propertyIsEnumerable)
|
||||
|
||||
var key
|
||||
function TestIsEnumerable(handler) {
|
||||
var o = Proxy.create(handler)
|
||||
assertTrue(Object.prototype.propertyIsEnumerable.call(o, "a"))
|
||||
assertEquals("a", key)
|
||||
assertTrue(Object.prototype.propertyIsEnumerable.call(o, 2))
|
||||
assertEquals("2", key)
|
||||
assertFalse(Object.prototype.propertyIsEnumerable.call(o, "z"))
|
||||
assertEquals("z", key)
|
||||
}
|
||||
|
||||
TestIsEnumerable({
|
||||
getOwnPropertyDescriptor: function(k) {
|
||||
key = k; return {enumerable: k < "z", configurable: true}
|
||||
},
|
||||
})
|
||||
|
||||
TestIsEnumerable({
|
||||
getOwnPropertyDescriptor: function(k) {
|
||||
return this.getOwnPropertyDescriptor2(k)
|
||||
},
|
||||
getOwnPropertyDescriptor2: function(k) {
|
||||
key = k; return {enumerable: k < "z", configurable: true}
|
||||
},
|
||||
})
|
||||
|
||||
TestIsEnumerable({
|
||||
getOwnPropertyDescriptor: function(k) {
|
||||
key = k; return {get enumerable() { return k < "z" }, configurable: true}
|
||||
},
|
||||
})
|
||||
|
||||
TestIsEnumerable(Proxy.create({
|
||||
get: function(pr, pk) {
|
||||
return function(k) {
|
||||
key = k; return {enumerable: k < "z", configurable: true}
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
Loading…
Reference in New Issue
Block a user