diff options
author | Andreas Kling <kling@serenityos.org> | 2021-05-18 11:15:49 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-05-18 11:18:19 +0200 |
commit | 3ee092cd0cacb999469e50aa5ff220e397df2d79 (patch) | |
tree | eccd068c825e6be502ebe2f8dacde40b9e7298ed /Userland/Libraries | |
parent | 94569e52f561eaa7fe4cb9f570792e063eb6922a (diff) | |
download | serenity-3ee092cd0cacb999469e50aa5ff220e397df2d79.zip |
LibJS: Implement Object.hasOwn() :^)
This is currently a TC39 Stage 2 proposal, but let's go for it!
https://github.com/tc39/proposal-accessible-object-hasownproperty
I wrote the C++, @linusg found bugs and wrote the test.
Diffstat (limited to 'Userland/Libraries')
4 files changed, 49 insertions, 0 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h index fbccb97cac..cf740626c2 100644 --- a/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h +++ b/Userland/Libraries/LibJS/Runtime/CommonPropertyNames.h @@ -135,6 +135,7 @@ namespace JS { P(globalThis) \ P(groups) \ P(has) \ + P(hasOwn) \ P(hasOwnProperty) \ P(hypot) \ P(ignoreCase) \ diff --git a/Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp b/Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp index 5c1caabfa2..fddded47f1 100644 --- a/Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp @@ -45,6 +45,7 @@ void ObjectConstructor::initialize(GlobalObject& global_object) 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); + define_native_function(vm.names.hasOwn, has_own, 2, attr); } ObjectConstructor::~ObjectConstructor() @@ -310,4 +311,15 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::create) return object; } +JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::has_own) +{ + auto* object = vm.argument(0).to_object(global_object); + if (vm.exception()) + return {}; + auto string_or_symbol = StringOrSymbol::from_value(global_object, vm.argument(1)); + if (vm.exception()) + return {}; + return Value(object->has_own_property(string_or_symbol)); +} + } diff --git a/Userland/Libraries/LibJS/Runtime/ObjectConstructor.h b/Userland/Libraries/LibJS/Runtime/ObjectConstructor.h index 8a4e3361d6..b616a5ffb6 100644 --- a/Userland/Libraries/LibJS/Runtime/ObjectConstructor.h +++ b/Userland/Libraries/LibJS/Runtime/ObjectConstructor.h @@ -42,6 +42,7 @@ private: JS_DECLARE_NATIVE_FUNCTION(values); JS_DECLARE_NATIVE_FUNCTION(entries); JS_DECLARE_NATIVE_FUNCTION(create); + JS_DECLARE_NATIVE_FUNCTION(has_own); }; } diff --git a/Userland/Libraries/LibJS/Tests/builtins/Object/Object.hasOwn.js b/Userland/Libraries/LibJS/Tests/builtins/Object/Object.hasOwn.js new file mode 100644 index 0000000000..1ea82a309a --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/Object/Object.hasOwn.js @@ -0,0 +1,35 @@ +describe("basic functionality", () => { + test("length", () => { + expect(Object.hasOwn).toHaveLength(2); + }); + + test("returns true for existent own property", () => { + const o = { foo: "bar" }; + expect(Object.hasOwn(o, "foo")).toBeTrue(); + }); + + test("returns false for non-existent own property", () => { + const o = {}; + expect(Object.hasOwn(o, "foo")).toBeFalse(); + }); + + test("returns false for existent prototype chain property", () => { + const o = {}; + Object.prototype.foo = "bar"; + expect(Object.hasOwn(o, "foo")).toBeFalse(); + }); +}); + +describe("errors", () => { + test("null argument", () => { + expect(() => { + Object.hasOwn(null); + }).toThrowWithMessage(TypeError, "ToObject on null or undefined"); + }); + + test("undefined argument", () => { + expect(() => { + Object.hasOwn(undefined); + }).toThrowWithMessage(TypeError, "ToObject on null or undefined"); + }); +}); |