From aa0f8c09d8ff86c7bf736d3a2440f88df4ee75d5 Mon Sep 17 00:00:00 2001 From: Kevin Eady <8634912+KevinEady@users.noreply.github.com> Date: Wed, 4 Mar 2026 19:02:06 +0100 Subject: [PATCH] feat: add Object::GetPrototype and Object::SetPrototype Fixes: #1691 --- doc/object.md | 22 ++++++++++++++++++++++ napi-inl.h | 13 +++++++++++++ napi.h | 6 ++++++ test/object/object.cc | 18 ++++++++++++++++++ test/object/object.js | 13 +++++++++++++ 5 files changed, 72 insertions(+) diff --git a/doc/object.md b/doc/object.md index a4d3280b8..fb7d53ad1 100644 --- a/doc/object.md +++ b/doc/object.md @@ -241,6 +241,28 @@ from being added to it and marking all existing properties as non-configurable. Values of present properties can still be changed as long as they are writable. +### GetPrototype() + +```cpp +Napi::Object Napi::Object::GetPrototype() const; +``` + +The `Napi::Object::GetPrototype()` method returns the prototype of the object. + +### SetPrototype() + +```cpp +bool Napi::Object::SetPrototype(const Napi::Object& value) const; +``` + +- `[in] value`: The prototype value. + +The `Napi::Object::SetPrototype()` method sets the prototype of the object. + +**NOTE**: The support for `Napi::Object::SetPrototype` is only available when +using `NAPI_EXPERIMENTAL` and building against Node.js headers that support this +feature. + ### operator\[\]() ```cpp diff --git a/napi-inl.h b/napi-inl.h index 0f1717ecd..a16465653 100644 --- a/napi-inl.h +++ b/napi-inl.h @@ -1966,6 +1966,19 @@ inline MaybeOrValue Object::Seal() const { } #endif // NAPI_VERSION >= 8 +inline MaybeOrValue Object::GetPrototype() const { + napi_value result; + napi_status status = napi_get_prototype(_env, _value, &result); + NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, Object(_env, result), Object); +} + +#ifdef NODE_API_EXPERIMENTAL_HAS_SET_PROTOTYPE +inline MaybeOrValue Object::SetPrototype(const Object& value) const { + napi_status status = node_api_set_prototype(_env, _value, value); + NAPI_RETURN_OR_THROW_IF_FAILED(_env, status, status == napi_ok, bool); +} +#endif + //////////////////////////////////////////////////////////////////////////////// // External class //////////////////////////////////////////////////////////////////////////////// diff --git a/napi.h b/napi.h index 013a9114d..abd8e6b7b 100644 --- a/napi.h +++ b/napi.h @@ -1118,6 +1118,12 @@ class Object : public TypeTaggable { /// https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-getprototypeof MaybeOrValue Seal() const; #endif // NAPI_VERSION >= 8 + + MaybeOrValue GetPrototype() const; + +#ifdef NODE_API_EXPERIMENTAL_HAS_SET_PROTOTYPE + MaybeOrValue SetPrototype(const Object& value) const; +#endif }; template diff --git a/test/object/object.cc b/test/object/object.cc index be0bcadde..60aae768f 100644 --- a/test/object/object.cc +++ b/test/object/object.cc @@ -343,6 +343,19 @@ Value InstanceOf(const CallbackInfo& info) { return Boolean::New(info.Env(), MaybeUnwrap(obj.InstanceOf(constructor))); } +Value GetPrototype(const CallbackInfo& info) { + Object obj = info[0].UnsafeAs(); + return MaybeUnwrap(obj.GetPrototype()); +} + +#ifdef NODE_API_EXPERIMENTAL_HAS_SET_PROTOTYPE +Value SetPrototype(const CallbackInfo& info) { + Object obj = info[0].UnsafeAs(); + Object prototype = info[1].UnsafeAs(); + return Boolean::New(info.Env(), MaybeUnwrap(obj.SetPrototype(prototype))); +} +#endif // NODE_API_EXPERIMENTAL_HAS_SET_PROTOTYPE + Object InitObject(Env env) { Object exports = Object::New(env); @@ -426,5 +439,10 @@ Object InitObject(Env env) { Function::New(env, SubscriptSetWithCppStyleString); exports["subscriptSetAtIndex"] = Function::New(env, SubscriptSetAtIndex); + exports["getPrototype"] = Function::New(env, GetPrototype); +#ifdef NODE_API_EXPERIMENTAL_HAS_SET_PROTOTYPE + exports["setPrototype"] = Function::New(env, SetPrototype); +#endif // NODE_API_EXPERIMENTAL_HAS_SET_PROTOTYPE + return exports; } diff --git a/test/object/object.js b/test/object/object.js index 6cd9735e9..06e41daa0 100644 --- a/test/object/object.js +++ b/test/object/object.js @@ -215,4 +215,17 @@ function test (binding) { c: 3 }); } + + { + const prototype = {}; + const obj = Object.create(prototype); + assert.strictEqual(binding.object.getPrototype(obj), prototype); + } + + if ('setPrototype' in binding.object) { + const prototype = {}; + const obj = Object.create(null); + assert.strictEqual(binding.object.setPrototype(obj, prototype), true); + assert.strictEqual(Object.getPrototypeOf(obj), prototype); + } }