Преглед на файлове

LibJS: Implement Object.create()

Linus Groh преди 4 години
родител
ревизия
9cd010167a

+ 1 - 0
Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h

@@ -94,6 +94,7 @@ namespace JS {
     P(cosh)                                  \
     P(count)                                 \
     P(countReset)                            \
+    P(create)                                \
     P(debug)                                 \
     P(defineProperties)                      \
     P(defineProperty)                        \

+ 28 - 0
Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp

@@ -64,6 +64,7 @@ void ObjectConstructor::initialize(GlobalObject& global_object)
     define_native_function(vm.names.keys, keys, 1, attr);
     define_native_function(vm.names.values, values, 1, attr);
     define_native_function(vm.names.entries, entries, 1, attr);
+    define_native_function(vm.names.create, create, 2, attr);
 }
 
 ObjectConstructor::~ObjectConstructor()
@@ -311,4 +312,31 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::entries)
     return Array::create_from(global_object, obj_arg->get_enumerable_own_property_names(PropertyKind::KeyAndValue));
 }
 
+// 20.1.2.2 Object.create, https://tc39.es/ecma262/#sec-object.create
+JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::create)
+{
+    auto prototype_value = vm.argument(0);
+    auto properties = vm.argument(1);
+
+    Object* prototype;
+    if (prototype_value.is_null()) {
+        prototype = nullptr;
+    } else if (prototype_value.is_object()) {
+        prototype = &prototype_value.as_object();
+    } else {
+        vm.throw_exception<TypeError>(global_object, ErrorType::ObjectPrototypeWrongType);
+        return {};
+    }
+
+    auto* object = Object::create_empty(global_object);
+    object->set_prototype(prototype);
+
+    if (!properties.is_undefined()) {
+        object->define_properties(properties);
+        if (vm.exception())
+            return {};
+    }
+    return object;
+}
+
 }

+ 1 - 0
Userland/Libraries/LibJS/Runtime/ObjectConstructor.h

@@ -61,6 +61,7 @@ private:
     JS_DECLARE_NATIVE_FUNCTION(keys);
     JS_DECLARE_NATIVE_FUNCTION(values);
     JS_DECLARE_NATIVE_FUNCTION(entries);
+    JS_DECLARE_NATIVE_FUNCTION(create);
 };
 
 }

+ 57 - 0
Userland/Libraries/LibJS/Tests/builtins/Object/Object.create.js

@@ -0,0 +1,57 @@
+test("length is 2", () => {
+    expect(Object.create).toHaveLength(2);
+});
+
+describe("errors", () => {
+    test("non-object protpotype value", () => {
+        expect(() => Object.create(42)).toThrowWithMessage(
+            TypeError,
+            "Prototype must be an object or null"
+        );
+    });
+});
+
+describe("normal behavior", () => {
+    test("creates object with given prototype", () => {
+        let o;
+
+        o = Object.create(null);
+        expect(o).toEqual({});
+        expect(Object.getPrototypeOf(o)).toBe(null);
+
+        const p = {};
+        o = Object.create(p);
+        expect(o).toEqual({});
+        expect(Object.getPrototypeOf(o)).toBe(p);
+    });
+
+    test("creates object with properties from propertiesObject, if given", () => {
+        const o = Object.create(
+            {},
+            {
+                foo: {
+                    writable: true,
+                    configurable: true,
+                    value: "foo",
+                },
+                bar: {
+                    enumerable: true,
+                    value: "bar",
+                },
+            }
+        );
+        expect(Object.getOwnPropertyNames(o)).toEqual(["foo", "bar"]);
+        expect(Object.getOwnPropertyDescriptor(o, "foo")).toEqual({
+            value: "foo",
+            writable: true,
+            enumerable: false,
+            configurable: true,
+        });
+        expect(Object.getOwnPropertyDescriptor(o, "bar")).toEqual({
+            value: "bar",
+            writable: false,
+            enumerable: true,
+            configurable: false,
+        });
+    });
+});