#530: Object.getOwnPropertyDescriptors M1245024 M1279303

This commit is contained in:
Cameron Kaiser 2018-10-29 20:02:06 -07:00
parent a8fa640688
commit 052586b55c
21 changed files with 439 additions and 0 deletions

View File

@ -1204,6 +1204,7 @@ static const JSFunctionSpec object_static_methods[] = {
JS_SELF_HOSTED_FN("getPrototypeOf", "ObjectGetPrototypeOf", 1, JSPROP_DEFINE_LATE),
JS_FN("setPrototypeOf", obj_setPrototypeOf, 2, 0),
JS_FN("getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor,2, 0),
JS_SELF_HOSTED_FN("getOwnPropertyDescriptors", "ObjectGetOwnPropertyDescriptors", 1, JSPROP_DEFINE_LATE),
JS_FN("keys", obj_keys, 1, 0),
JS_FN("values", obj_values, 1, 0),
JS_FN("entries", obj_entries, 1, 0),

View File

@ -41,6 +41,33 @@ function ObjectStaticAssign(target, firstSource) {
return to;
}
// ES stage 4 proposal
function ObjectGetOwnPropertyDescriptors(O) {
// Step 1.
var obj = ToObject(O);
// Step 2.
var keys = OwnPropertyKeys(obj, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS);
// Step 3.
var descriptors = {};
// Step 4.
for (var index = 0, len = keys.length; index < len; index++) {
var key = keys[index];
// Steps 4.a-b.
var desc = std_Object_getOwnPropertyDescriptor(obj, key);
// Step 4.c.
if (typeof desc !== "undefined")
_DefineDataProperty(descriptors, key, desc);
}
// Step 5.
return descriptors;
}
/* ES6 draft rev 32 (2015 Feb 2) 19.1.2.9. */
function ObjectGetPrototypeOf(obj) {
return std_Reflect_getPrototypeOf(ToObject(obj));

View File

@ -0,0 +1,38 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors on a proxy with duplicate ownKeys should work
esid: pending
author: Jordan Harband
features: [Proxy]
---*/
var i = 0;
var descriptors = [
{ enumerable: false, value: "A1", writable: true, configurable: true },
{ enumerable: true, value: "A2", writable: true, configurable: true }
];
var log = '';
var proxy = new Proxy({}, {
ownKeys() {
log += 'ownKeys|';
return ['DUPLICATE', 'DUPLICATE', 'DUPLICATE'];
},
getOwnPropertyDescriptor(t, name) {
log += 'getOwnPropertyDescriptor:' + name + '|';
return descriptors[i++];
}
});
var result = Object.getOwnPropertyDescriptors(proxy);
assert.sameValue(result.hasOwnProperty('DUPLICATE'), true);
var lastDescriptor = descriptors[descriptors.length - 1];
assert.notSameValue(result.DUPLICATE, lastDescriptor);
assert.sameValue(result.DUPLICATE.enumerable, lastDescriptor.enumerable);
assert.sameValue(result.DUPLICATE.configurable, lastDescriptor.configurable);
assert.sameValue(result.DUPLICATE.value, lastDescriptor.value);
assert.sameValue(result.DUPLICATE.writable, lastDescriptor.writable);
assert.sameValue(log, 'ownKeys|getOwnPropertyDescriptor:DUPLICATE|getOwnPropertyDescriptor:DUPLICATE|getOwnPropertyDescriptor:DUPLICATE|');

View File

@ -0,0 +1,16 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors should fail if given a null or undefined value
esid: pending
author: Jordan Harband
---*/
assert.throws(TypeError, function () {
Object.getOwnPropertyDescriptors(null);
});
assert.throws(TypeError, function () {
Object.getOwnPropertyDescriptors(undefined);
});

View File

@ -0,0 +1,16 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors should have length 1
esid: pending
author: Jordan Harband
includes: [propertyHelper.js]
---*/
assert.sameValue(Object.getOwnPropertyDescriptors.length, 1, 'Expected Object.getOwnPropertyDescriptors.length to be 1');
var desc = Object.getOwnPropertyDescriptor(Object.getOwnPropertyDescriptors, 'length');
assertEq(desc.enumerable, false);
assertEq(desc.writable, false);
assertEq(desc.configurable, true);

View File

@ -0,0 +1,20 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors should have name property with value 'getOwnPropertyDescriptors'
esid: pending
author: Jordan Harband
includes: [propertyHelper.js]
---*/
assert.sameValue(
Object.getOwnPropertyDescriptors.name,
'getOwnPropertyDescriptors',
'Expected Object.getOwnPropertyDescriptors.name to be "getOwnPropertyDescriptors"'
);
var desc = Object.getOwnPropertyDescriptor(Object.getOwnPropertyDescriptors, 'name');
assertEq(desc.enumerable, false);
assertEq(desc.writable, false);
assertEq(desc.configurable, true);

View File

@ -0,0 +1,14 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors should be writable, non-enumerable, and configurable
esid: pending
author: Jordan Harband
includes: [propertyHelper.js]
---*/
var desc = Object.getOwnPropertyDescriptor(Object, 'getOwnPropertyDescriptors');
assertEq(desc.enumerable, false);
assertEq(desc.writable, true);
assertEq(desc.configurable, true);

View File

@ -0,0 +1,43 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors does not see inherited properties.
esid: pending
author: Jordan Harband
---*/
var F = function () {};
F.prototype.a = {};
F.prototype.b = {};
var f = new F();
var bValue = {};
f.b = bValue; // shadow the prototype
Object.defineProperty(f, 'c', {
enumerable: false,
configurable: true,
writable: false,
value: {}
}); // solely an own property
var result = Object.getOwnPropertyDescriptors(f);
assert.sameValue(!!result.b, true, 'b has a descriptor');
assert.sameValue(!!result.c, true, 'c has a descriptor');
assert.sameValue(result.b.enumerable, true, 'b is enumerable');
assert.sameValue(result.b.configurable, true, 'b is configurable');
assert.sameValue(result.b.writable, true, 'b is writable');
assert.sameValue(result.b.value, bValue, 'bs value is `bValue`');
assert.sameValue(result.c.enumerable, false, 'c is enumerable');
assert.sameValue(result.c.configurable, true, 'c is configurable');
assert.sameValue(result.c.writable, false, 'c is writable');
assert.sameValue(result.c.value, f.c, 'cs value is `f.c`');
assert.sameValue(
Object.keys(result).length,
2,
'result has same number of own property names as f'
);

View File

@ -0,0 +1,13 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors should produce a normal object inheriting from Object.prototype
esid: pending
author: Jordan Harband
---*/
assert.sameValue(
Object.getPrototypeOf(Object.getOwnPropertyDescriptors({})),
Object.prototype
);

View File

@ -0,0 +1,34 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors should perform observable operations in the correct order
esid: pending
author: Jordan Harband
features: [Proxy]
includes: [proxyTrapsHelper.js]
---*/
var log = "";
var object = { a: 0, b: 0, c: 0 };
var handler = {
getOwnPropertyDescriptor: function (target, propertyKey) {
assert.sameValue(target, object, "getOwnPropertyDescriptor");
log += "|getOwnPropertyDescriptor:" + propertyKey;
return Object.getOwnPropertyDescriptor(target, propertyKey);
},
ownKeys: function (target) {
assert.sameValue(target, object, "ownKeys");
log += "|ownKeys";
return Object.getOwnPropertyNames(target);
}
};
var check = {
get: function (target, propertyKey, receiver) {
assertEq(propertyKey in target, true, "handler check: " + propertyKey);
return target[propertyKey];
}
};
var proxy = new Proxy(object, new Proxy(handler, check));
var result = Object.getOwnPropertyDescriptors(proxy);
assert.sameValue(log, "|ownKeys|getOwnPropertyDescriptor:a|getOwnPropertyDescriptor:b|getOwnPropertyDescriptor:c", 'log');

View File

@ -0,0 +1,16 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors accepts boolean primitives.
esid: pending
author: Jordan Harband
---*/
var trueResult = Object.getOwnPropertyDescriptors(true);
assert.sameValue(Object.keys(trueResult).length, 0, 'trueResult has 0 items');
var falseResult = Object.getOwnPropertyDescriptors(false);
assert.sameValue(Object.keys(falseResult).length, 0, 'falseResult has 0 items');

View File

@ -0,0 +1,15 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors accepts number primitives.
esid: pending
author: Jordan Harband
---*/
assert.sameValue(Object.keys(Object.getOwnPropertyDescriptors(0)).length, 0, '0 has zero descriptors');
assert.sameValue(Object.keys(Object.getOwnPropertyDescriptors(-0)).length, 0, '-0 has zero descriptors');
assert.sameValue(Object.keys(Object.getOwnPropertyDescriptors(Infinity)).length, 0, 'Infinity has zero descriptors');
assert.sameValue(Object.keys(Object.getOwnPropertyDescriptors(-Infinity)).length, 0, '-Infinity has zero descriptors');
assert.sameValue(Object.keys(Object.getOwnPropertyDescriptors(NaN)).length, 0, 'NaN has zero descriptors');
assert.sameValue(Object.keys(Object.getOwnPropertyDescriptors(Math.PI)).length, 0, 'Math.PI has zero descriptors');

View File

@ -0,0 +1,33 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors accepts string primitives.
esid: pending
author: Jordan Harband
---*/
var result = Object.getOwnPropertyDescriptors('abc');
assert.sameValue(Object.keys(result).length, 4, 'string has 4 descriptors');
assert.sameValue(result.length.configurable, false, 'length is not configurable');
assert.sameValue(result.length.enumerable, false, 'length is not enumerable');
assert.sameValue(result.length.writable, false, 'length is not writable');
assert.sameValue(result.length.value, 3, 'length is 3');
assert.sameValue(result[0].configurable, false, 'index 0 is not configurable');
assert.sameValue(result[0].enumerable, true, 'index 0 is enumerable');
assert.sameValue(result[0].writable, false, 'index 0 is not writable');
assert.sameValue(result[0].value, 'a', 'index 0 is "a"');
assert.sameValue(result[1].configurable, false, 'index 1 is not configurable');
assert.sameValue(result[1].enumerable, true, 'index 1 is enumerable');
assert.sameValue(result[1].writable, false, 'index 1 is not writable');
assert.sameValue(result[1].value, 'b', 'index 1 is "b"');
assert.sameValue(result[2].configurable, false, 'index 2 is not configurable');
assert.sameValue(result[2].enumerable, true, 'index 2 is enumerable');
assert.sameValue(result[2].writable, false, 'index 2 is not writable');
assert.sameValue(result[2].value, 'c', 'index 2 is "c"');

View File

@ -0,0 +1,13 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors accepts Symbol primitives.
esid: pending
author: Jordan Harband
features: [Symbol]
---*/
var result = Object.getOwnPropertyDescriptors(Symbol());
assert.sameValue(Object.keys(result).length, 0, 'symbol primitive has no descriptors');

View File

@ -0,0 +1,32 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors should filter out undefined OwnPropertyDescriptors
esid: sec-object.getownpropertydescriptors
author: Jordan Harband
featurewws: [Proxy]
includes: [proxyTrapsHelper.js]
---*/
var key = "a";
var ownKeys = [key];
var badProxyHandlers = {
getOwnPropertyDescriptor: function () {},
ownKeys: function () {
return ownKeys;
}
};
var proxy = new Proxy({}, badProxyHandlers);
var keys = Reflect.ownKeys(proxy);
assert.notSameValue(keys, ownKeys, 'Object.keys returns a new Array');
assert.sameValue(Array.isArray(keys), true, 'Object.keys returns an Array');
assert.sameValue(keys.length, ownKeys.length, 'keys and ownKeys have the same length');
assert.sameValue(keys[0], ownKeys[0], 'keys and ownKeys have the same contents');
var descriptor = Object.getOwnPropertyDescriptor(proxy, key);
assert.sameValue(descriptor, undefined, "Descriptor matches result of [[GetOwnPropertyDescriptor]] trap");
var result = Object.getOwnPropertyDescriptors(proxy);
assert.sameValue(key in result, false, "key is not present in result");

View File

@ -0,0 +1,27 @@
var assert = {
sameValue: assertEq,
notSameValue(a, b, msg) {
try {
assertEq(a, b);
throw "equal"
} catch (e) {
if (e === "equal")
throw new Error("Assertion failed: expected different values, got " + a);
}
},
throws(ctor, f) {
var fullmsg;
try {
f();
} catch (exc) {
if (exc instanceof ctor)
return;
fullmsg = "Assertion failed: expected exception " + ctor.name + ", got " + exc;
}
if (fullmsg === undefined)
fullmsg = "Assertion failed: expected exception " + ctor.name + ", no exception thrown";
if (msg !== undefined)
fullmsg += " - " + msg;
throw new Error(fullmsg);
}
}

View File

@ -0,0 +1,38 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: Object.getOwnPropertyDescriptors includes Symbol keys.
esid: pending
author: Jordan Harband
features: [Symbol]
---*/
var value = {};
var enumSym = Symbol('enum');
var nonEnumSym = Symbol('nonenum');
var symValue = Symbol('value');
var obj = { key: symValue };
obj[enumSym] = value;
Object.defineProperty(obj, nonEnumSym, { writable: true, enumerable: false, configurable: true, value: value });
var result = Object.getOwnPropertyDescriptors(obj);
assert.sameValue(Object.keys(result).length, 1, 'obj has 1 string-keyed descriptor');
assert.sameValue(Object.getOwnPropertySymbols(result).length, 2, 'obj has 2 symbol-keyed descriptors');
assert.sameValue(result.key.configurable, true, 'result.key is configurable');
assert.sameValue(result.key.enumerable, true, 'result.key is enumerable');
assert.sameValue(result.key.writable, true, 'result.key is writable');
assert.sameValue(result.key.value, symValue, 'result.key has value symValue');
assert.sameValue(result[enumSym].configurable, true, 'result[enumSym] is configurable');
assert.sameValue(result[enumSym].enumerable, true, 'result[enumSym] is enumerable');
assert.sameValue(result[enumSym].writable, true, 'result[enumSym] is writable');
assert.sameValue(result[enumSym].value, value, 'result[enumSym] has value `value`');
assert.sameValue(result[nonEnumSym].configurable, true, 'result[nonEnumSym] is configurable');
assert.sameValue(result[nonEnumSym].enumerable, false, 'result[nonEnumSym] is not enumerable');
assert.sameValue(result[nonEnumSym].writable, true, 'result[nonEnumSym] is writable');
assert.sameValue(result[nonEnumSym].value, value, 'result[nonEnumSym] has value `value`');

View File

@ -0,0 +1,21 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: >
Object.getOwnPropertyDescriptors should not have its behavior impacted by modifications to the global property Object
esid: pending
author: Jordan Harband
---*/
function fakeObject() {
$ERROR('The overriden version of Object was called!');
}
fakeObject.getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors;
fakeObject.keys = Object.keys;
var global = this;
global.Object = fakeObject;
assert.sameValue(Object, fakeObject, 'Sanity check failed: could not modify the global Object');
assert.sameValue(Object.keys(Object.getOwnPropertyDescriptors('a')).length, 2, 'Expected string primitive to have 2 descriptors');

View File

@ -0,0 +1,22 @@
// Copyright (C) 2016 Jordan Harband. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
description: >
Object.getOwnPropertyDescriptors should not have its behavior impacted by modifications to Object.getOwnPropertyDescriptor
esid: pending
author: Jordan Harband
---*/
function fakeObjectGetOwnPropertyDescriptor() {
$ERROR('The overriden version of Object.getOwnPropertyDescriptor was called!');
}
Object.getOwnPropertyDescriptor = fakeObjectGetOwnPropertyDescriptor;
assert.sameValue(
Object.getOwnPropertyDescriptor,
fakeObjectGetOwnPropertyDescriptor,
'Sanity check failed: could not modify the global Object.getOwnPropertyDescriptor'
);
assert.sameValue(Object.keys(Object.getOwnPropertyDescriptors({ a: 1 })).length, 1, 'Expected object with 1 key to have 1 descriptor');

View File