]> git.kaiwu.me - njs.git/commitdiff
Added Object.hasOwn().
authorVadim Zhestikov <v.zhestikov@f5.com>
Mon, 10 Nov 2025 17:50:48 +0000 (09:50 -0800)
committerVadimZhestikov <108960056+VadimZhestikov@users.noreply.github.com>
Fri, 14 Nov 2025 00:05:28 +0000 (16:05 -0800)
src/njs_atom_defs.h
src/njs_object.c
src/test/njs_unit_test.c

index 6328c34b8b5a7129c8e7e07d459079c351aaaee6..35dcbe12433ba1dabe3b721dae4de26caef661ac 100644 (file)
@@ -286,6 +286,7 @@ NJS_DEF_STRING(getMonth, "getMonth", 0, 0)
 NJS_DEF_STRING(global, "global", 0, 0)
 NJS_DEF_STRING(globalThis, "globalThis", 0, 0)
 NJS_DEF_STRING(groups, "groups", 0, 0)
+NJS_DEF_STRING(hasOwn, "hasOwn", 0, 0)
 NJS_DEF_STRING(hasOwnProperty, "hasOwnProperty", 0, 0)
 NJS_DEF_STRING(hasInstance, "hasInstance", 0, 0)
 NJS_DEF_STRING(hypot, "hypot", 0, 0)
index 0f277fea5687fbb62b26208d637b647f427c66e6..97f17d583bb2cccfaa4e3af1c63e32ce46d19a9c 100644 (file)
@@ -31,6 +31,9 @@ static njs_int_t njs_object_define_properties(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused, njs_value_t *retval);
 static njs_int_t njs_object_set_prototype(njs_vm_t *vm, njs_object_t *object,
     const njs_value_t *value);
+static njs_int_t njs_object_prototype_has_own_property(njs_vm_t *vm,
+    njs_value_t *args, njs_uint_t nargs, njs_index_t magic,
+    njs_value_t *retval);
 
 
 njs_object_t *
@@ -2274,8 +2277,10 @@ static const njs_object_prop_init_t  njs_object_constructor_properties[] =
     NJS_DECLARE_PROP_NATIVE(STRING_assign, njs_object_assign, 2, 0),
 
     NJS_DECLARE_PROP_NATIVE(STRING_is, njs_object_is, 2, 0),
-};
 
+    NJS_DECLARE_PROP_NATIVE(STRING_hasOwn,
+                            njs_object_prototype_has_own_property, 2, 1),
+};
 
 const njs_object_init_t  njs_object_constructor_init = {
     njs_object_constructor_properties,
@@ -2590,27 +2595,47 @@ njs_object_to_string(njs_vm_t *vm, njs_value_t *this, njs_value_t *retval)
 
 static njs_int_t
 njs_object_prototype_has_own_property(njs_vm_t *vm, njs_value_t *args,
-    njs_uint_t nargs, njs_index_t unused, njs_value_t *retval)
+    njs_uint_t nargs, njs_index_t magic, njs_value_t *retval)
 {
     njs_int_t             ret;
     njs_value_t           *value, *property, lvalue;
     njs_property_query_t  pq;
 
-    property = njs_lvalue_arg(&lvalue, args, nargs, 1);
+    if (magic == 0) {
+        /* hasOwnProperty. */
 
-    if (njs_slow_path(!njs_is_key(property))) {
-        ret = njs_value_to_key(vm, property, property);
-        if (njs_slow_path(ret != NJS_OK)) {
+        property = njs_lvalue_arg(&lvalue, args, nargs, 1 + magic);
+        if (njs_slow_path(!njs_is_key(property))) {
+            ret = njs_value_to_key(vm, property, property);
+            if (njs_slow_path(ret != NJS_OK)) {
+                return NJS_ERROR;
+            }
+        }
+
+        value = njs_argument(args, magic);
+        if (njs_is_null_or_undefined(value)) {
+            njs_type_error(vm, "cannot convert %s argument to object",
+                           njs_type_string(value->type));
             return NJS_ERROR;
         }
-    }
 
-    value = njs_argument(args, 0);
+    } else {
+        /* hasOwn. */
 
-    if (njs_is_null_or_undefined(value)) {
-        njs_type_error(vm, "cannot convert %s argument to object",
-                       njs_type_string(value->type));
-        return NJS_ERROR;
+        value = njs_lvalue_arg(&lvalue, args, nargs, magic);
+        if (njs_is_null_or_undefined(value)) {
+            njs_type_error(vm, "cannot convert %s argument to object",
+                           njs_type_string(value->type));
+            return NJS_ERROR;
+        }
+
+        property = njs_lvalue_arg(&lvalue, args, nargs, 1 + magic);
+        if (njs_slow_path(!njs_is_key(property))) {
+            ret = njs_value_to_key(vm, property, property);
+            if (njs_slow_path(ret != NJS_OK)) {
+                return NJS_ERROR;
+            }
+        }
     }
 
     njs_property_query_init(&pq, NJS_PROPERTY_QUERY_GET, 1);
index 67c57d19eadc0eefe820ee409f7654a27d4a6f6b..c0f1f1d365208364cf2db3a6192d708ae58a4762 100644 (file)
@@ -15108,6 +15108,83 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("Object.prototype.hasOwnProperty('hasOwnProperty')"),
       njs_str("true") },
 
+    { njs_str("var o = {a:1}; Object.hasOwn(o, 'a')"),
+      njs_str("true") },
+
+    { njs_str("var o = Object.create({a:2}); Object.hasOwn(o, 'a')"),
+      njs_str("false") },
+
+    { njs_str("var o = {a:1}; Object.hasOwn(o, 'b')"),
+      njs_str("false") },
+
+    { njs_str("var o = Object.create(null); o.a = 1; Object.hasOwn(o, 'a')"),
+      njs_str("true") },
+
+    { njs_str("var o = Object.create(null); Object.hasOwn(o, 'hasOwnProperty')"),
+      njs_str("false") },
+
+    { njs_str("var o = {hasOwnProperty: 1}; Object.hasOwn(o, 'hasOwnProperty')"),
+      njs_str("true") },
+
+    { njs_str("var o = {a:1}; o.hasOwnProperty = function(){return false}; "
+              "Object.hasOwn(o, 'a')"),
+      njs_str("true") },
+
+    { njs_str("Object.hasOwn(null, 'a')"),
+      njs_str("TypeError: cannot convert null argument to object") },
+
+    { njs_str("Object.hasOwn(undefined, 'a')"),
+      njs_str("TypeError: cannot convert undefined argument to object") },
+
+    { njs_str("Object.hasOwn(1, 'toString')"),
+      njs_str("true") },
+
+    { njs_str("Object.hasOwn('abc', '0')"),
+      njs_str("true") },
+
+    { njs_str("Object.hasOwn('abc', '3')"),
+      njs_str("false") },
+
+    { njs_str("Object.hasOwn('abc', 'length')"),
+      njs_str("true") },
+
+    { njs_str("Object.hasOwn([1,2], '0')"),
+      njs_str("true") },
+
+    { njs_str("Object.hasOwn([,2], '0')"),
+      njs_str("false") },
+
+    { njs_str("Object.hasOwn([,2], '1')"),
+      njs_str("true") },
+
+    { njs_str("Object.hasOwn([], 'length')"),
+      njs_str("true") },
+
+    { njs_str("var s = Symbol('test'); var o = {}; o[s] = 1; Object.hasOwn(o, s)"),
+      njs_str("true") },
+
+    { njs_str("var s1 = Symbol('test'); var s2 = Symbol('test'); "
+              "var o = {}; o[s1] = 1; Object.hasOwn(o, s2)"),
+      njs_str("false") },
+
+    { njs_str("Object.hasOwn({}, Symbol.iterator)"),
+      njs_str("false") },
+
+    { njs_str("Object.hasOwn()"),
+      njs_str("TypeError: cannot convert ") },
+
+    { njs_str("Object.hasOwn({})"),
+      njs_str("false") },
+
+    { njs_str("var o = {}; Object.hasOwn(o)"),
+      njs_str("false") },
+
+    { njs_str("Object.hasOwn.length"),
+      njs_str("2") },
+
+    { njs_str("Object.hasOwn.name"),
+      njs_str("hasOwn") },
+
     { njs_str("var o = {};"
                  "Object.defineProperty(o, 'a', {get:undefined, set:undefined}).a"),
       njs_str("undefined") },