Bug 492840 - ES5: Implement Object.create. r=mrbkap

This commit is contained in:
Jeff Walden 2009-09-08 15:59:14 -07:00
parent 9613c2771b
commit 49c30c2502
2 changed files with 118 additions and 0 deletions

View File

@ -2756,6 +2756,71 @@ obj_defineProperties(JSContext* cx, uintN argc, jsval* vp)
return JS_TRUE;
}
/* ES5 15.2.3.5: Object.create(O [, Properties]) */
static JSBool
obj_create(JSContext *cx, uintN argc, jsval *vp)
{
if (argc == 0) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
"Object.create", "0", "s");
return JS_FALSE;
}
jsval v = vp[2];
if (!JSVAL_IS_OBJECT(vp[2])) {
char *bytes = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL);
if (!bytes)
return JS_FALSE;
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
bytes, "not an object or null");
JS_free(cx, bytes);
return JS_FALSE;
}
/*
* It's plausible that it's safe to just use the context's global object,
* but since we're not completely sure, better safe than sorry.
*/
JSObject *obj =
js_NewObjectWithGivenProto(cx, &js_ObjectClass, JSVAL_TO_OBJECT(v), JS_GetScopeChain(cx));
if (!obj)
return JS_FALSE;
*vp = OBJECT_TO_JSVAL(obj); /* Root and prepare for eventual return. */
/* 15.2.3.5 step 4. */
if (argc > 1 && vp[3] != JSVAL_VOID) {
if (JSVAL_IS_PRIMITIVE(vp[3])) {
js_ReportValueError(cx, JSMSG_NOT_NONNULL_OBJECT, -1, vp[3], NULL);
return JS_FALSE;
}
JSObject *props = JSVAL_TO_OBJECT(vp[3]);
JSAutoIdArray ida(cx, JS_Enumerate(cx, props));
if (!ida)
return JS_FALSE;
AutoDescriptorArray descs(cx);
size_t len = ida.length();
for (size_t i = 0; i < len; i++) {
PropertyDescriptor desc;
jsid id = ida[i];
if (!JS_GetPropertyById(cx, props, id, &vp[1]) || !desc.initialize(cx, id, vp[1]) ||
!descs.append(desc)) {
return JS_FALSE;
}
}
bool dummy;
for (size_t i = 0; i < len; i++) {
if (!DefineProperty(cx, obj, descs[i], true, &dummy))
return JS_FALSE;
}
}
/* 5. Return obj. */
return JS_TRUE;
}
#if JS_HAS_OBJ_WATCHPOINT
const char js_watch_str[] = "watch";
@ -2807,6 +2872,7 @@ static JSFunctionSpec object_static_methods[] = {
JS_FN("keys", obj_keys, 1,0),
JS_FN("defineProperty", obj_defineProperty, 3,0),
JS_FN("defineProperties", obj_defineProperties, 2,0),
JS_FN("create", obj_create, 2,0),
JS_FS_END
};

View File

@ -0,0 +1,52 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
var gTestfile = '15.2.3.5-01.js';
//-----------------------------------------------------------------------------
var BUGNUMBER = 492840;
var summary = 'ES5 Object.create(O [, Properties])';
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
assertEq("create" in Object, true);
assertEq(Object.create.length, 2);
var o, desc, props, proto;
o = Object.create(null);
assertEq(Object.getPrototypeOf(o), null, "bad null-proto");
o = Object.create(null, { a: { value: 17, enumerable: false } });
assertEq(Object.getPrototypeOf(o), null, "bad null-proto");
assertEq("a" in o, true);
desc = Object.getOwnPropertyDescriptor(o, "a");
assertEq(desc !== undefined, true, "no descriptor?");
assertEq(desc.value, 17);
assertEq(desc.enumerable, false);
assertEq(desc.configurable, false);
assertEq(desc.writable, false);
props = Object.create({ bar: 15 });
Object.defineProperty(props, "foo", { enumerable: false, value: 42 });
proto = { baz: 12 };
o = Object.create(proto, props);
assertEq(Object.getPrototypeOf(o), proto);
assertEq(Object.getOwnPropertyDescriptor(o, "foo"), undefined);
assertEq("foo" in o, false);
assertEq(Object.getOwnPropertyDescriptor(o, "bar"), undefined);
assertEq("bar" in o, false);
assertEq(Object.getOwnPropertyDescriptor(o, "baz"), undefined);
assertEq(o.baz, 12);
assertEq(o.hasOwnProperty("baz"), false);
/******************************************************************************/
reportCompare(true, true);
print("All tests passed!");