diff --git a/jerry-core/api/jerryscript.c b/jerry-core/api/jerryscript.c index b1ea96582..97f527c4e 100644 --- a/jerry-core/api/jerryscript.c +++ b/jerry-core/api/jerryscript.c @@ -3215,28 +3215,8 @@ jerry_object_has_own (const jerry_value_t object, /**< object value */ ecma_object_t *obj_p = ecma_get_object_from_value (object); ecma_string_t *prop_name_p = ecma_get_prop_name_from_value (key); -#if JERRY_BUILTIN_PROXY - if (ECMA_OBJECT_IS_PROXY (obj_p)) - { - ecma_property_descriptor_t prop_desc; - - ecma_value_t status = ecma_proxy_object_get_own_property_descriptor (obj_p, prop_name_p, &prop_desc); - - if (ecma_is_value_true (status)) - { - ecma_free_property_descriptor (&prop_desc); - } - - return jerry_return (status); - } -#endif /* JERRY_BUILTIN_PROXY */ - -#if JERRY_BUILTIN_TYPEDARRAY - return jerry_return (ecma_op_ordinary_object_has_own_property (obj_p, prop_name_p)); -#else /* !JERRY_BUILTIN_TYPEDARRAY */ - return ecma_op_ordinary_object_has_own_property (obj_p, prop_name_p); -#endif /* JERRY_BUILTIN_TYPEDARRAY */ -} /* jerry_object_has_own */ + return jerry_return (ecma_op_object_has_own_property (obj_p, prop_name_p)); +} /* jerry_has_own_property */ /** * Checks whether the object has the given internal property. diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.c index 71417fad5..e57af2ec3 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-object-prototype.c @@ -132,23 +132,7 @@ static ecma_value_t ecma_builtin_object_prototype_object_has_own_property (ecma_object_t *obj_p, /**< this argument */ ecma_string_t *prop_name_p) /**< first argument */ { -#if JERRY_BUILTIN_PROXY - if (ECMA_OBJECT_IS_PROXY (obj_p)) - { - ecma_property_descriptor_t prop_desc; - - ecma_value_t status = ecma_proxy_object_get_own_property_descriptor (obj_p, prop_name_p, &prop_desc); - - if (ecma_is_value_true (status)) - { - ecma_free_property_descriptor (&prop_desc); - } - - return status; - } -#endif /* JERRY_BUILTIN_PROXY */ - - return ecma_op_ordinary_object_has_own_property (obj_p, prop_name_p); + return ecma_op_object_has_own_property (obj_p, prop_name_p); } /* ecma_builtin_object_prototype_object_has_own_property */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-object.c b/jerry-core/ecma/builtin-objects/ecma-builtin-object.c index b94cb129a..e355e6871 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-object.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-object.c @@ -63,6 +63,7 @@ enum ECMA_OBJECT_ROUTINE_ASSIGN, ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_DESCRIPTOR, ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_DESCRIPTORS, + ECMA_OBJECT_ROUTINE_HAS_OWN, ECMA_OBJECT_ROUTINE_GET_PROTOTYPE_OF, ECMA_OBJECT_ROUTINE_FROM_ENTRIES, ECMA_OBJECT_ROUTINE_KEYS, @@ -1491,6 +1492,20 @@ ecma_builtin_object_dispatch_routine (uint8_t builtin_routine_id, /**< built-in break; } #if JERRY_ESNEXT + case ECMA_OBJECT_ROUTINE_HAS_OWN: + { + ecma_string_t *prop_name_p = ecma_op_to_property_key (arg2); + + if (prop_name_p == NULL) + { + result = ECMA_VALUE_ERROR; + break; + } + + result = ecma_op_object_has_own_property (obj_p, prop_name_p); + ecma_deref_ecma_string (prop_name_p); + break; + } case ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_DESCRIPTORS: { result = ecma_builtin_object_object_get_own_property_descriptors (obj_p); diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-object.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-object.inc.h index 7f79d4e5a..b046141b3 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-object.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-object.inc.h @@ -54,6 +54,7 @@ ROUTINE (LIT_MAGIC_STRING_VALUES, ECMA_OBJECT_ROUTINE_VALUES, 1, 1) ROUTINE (LIT_MAGIC_STRING_KEYS, ECMA_OBJECT_ROUTINE_KEYS, 1, 1) ROUTINE (LIT_MAGIC_STRING_GET_OWN_PROPERTY_DESCRIPTOR_UL, ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_DESCRIPTOR, 2, 2) #if JERRY_ESNEXT +ROUTINE (LIT_MAGIC_STRING_HAS_OWN_UL, ECMA_OBJECT_ROUTINE_HAS_OWN, 2, 2) ROUTINE (LIT_MAGIC_STRING_GET_OWN_PROPERTY_DESCRIPTORS_UL, ECMA_OBJECT_ROUTINE_GET_OWN_PROPERTY_DESCRIPTORS, 1, 1) ROUTINE (LIT_MAGIC_STRING_OBJECT_FROM_ENTRIES, ECMA_OBJECT_ROUTINE_FROM_ENTRIES, 1, 1) #endif /* JERRY_ESNEXT */ diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index 2ccc6f59a..b6462ddc1 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -3410,6 +3410,35 @@ ecma_op_ordinary_object_has_own_property (ecma_object_t *object_p, /**< the obje return ecma_make_boolean_value (ECMA_PROPERTY_IS_FOUND (property)); } /* ecma_op_ordinary_object_has_own_property */ +/** + * Checks whether an object (excluding prototypes) has a named property. Handles proxy objects too. + * + * @return true - if property is found + * false - otherwise + */ +ecma_value_t +ecma_op_object_has_own_property (ecma_object_t *object_p, /**< the object */ + ecma_string_t *property_name_p) /**< property name */ +{ +#if JERRY_BUILTIN_PROXY + if (ECMA_OBJECT_IS_PROXY (object_p)) + { + ecma_property_descriptor_t prop_desc; + + ecma_value_t status = ecma_proxy_object_get_own_property_descriptor (object_p, property_name_p, &prop_desc); + + if (ecma_is_value_true (status)) + { + ecma_free_property_descriptor (&prop_desc); + } + + return status; + } +#endif /* JERRY_BUILTIN_PROXY */ + + return ecma_op_ordinary_object_has_own_property (object_p, property_name_p); +} /* ecma_op_object_has_own_property */ + #if JERRY_BUILTIN_WEAKREF || JERRY_BUILTIN_CONTAINER /** diff --git a/jerry-core/ecma/operations/ecma-objects.h b/jerry-core/ecma/operations/ecma-objects.h index e148b4db4..31c51faff 100644 --- a/jerry-core/ecma/operations/ecma-objects.h +++ b/jerry-core/ecma/operations/ecma-objects.h @@ -58,6 +58,7 @@ ecma_property_t ecma_op_object_get_own_property (ecma_object_t *object_p, ecma_property_ref_t *property_ref_p, uint32_t options); ecma_value_t ecma_op_ordinary_object_has_own_property (ecma_object_t *object_p, ecma_string_t *property_name_p); +ecma_value_t ecma_op_object_has_own_property (ecma_object_t *object_p, ecma_string_t *property_name_p); ecma_value_t ecma_op_object_has_property (ecma_object_t *object_p, ecma_string_t *property_name_p); ecma_value_t ecma_op_object_find_own (ecma_value_t base_value, ecma_object_t *object_p, ecma_string_t *property_name_p); ecma_value_t ecma_op_object_find (ecma_object_t *object_p, ecma_string_t *property_name_p); diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index 7b2e7a91e..b6eabcf16 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -409,6 +409,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_DAY_UL, "getDay") #if JERRY_BUILTIN_REGEXP LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GLOBAL, "global") #endif /* JERRY_BUILTIN_REGEXP */ +#if JERRY_ESNEXT +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_HAS_OWN_UL, "hasOwn") +#endif /* JERRY_ESNEXT */ #if JERRY_BUILTIN_TYPEDARRAY LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IS_VIEW_UL, "isView") #endif /* JERRY_BUILTIN_TYPEDARRAY */ diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini index f2dc3e30d..d2235f46e 100644 --- a/jerry-core/lit/lit-magic-strings.ini +++ b/jerry-core/lit/lit-magic-strings.ini @@ -146,6 +146,7 @@ LIT_MAGIC_STRING_VALUE = "value" LIT_MAGIC_STRING_SOURCE_NAME_EVAL = "" LIT_MAGIC_STRING_BIGINT_UL = "BigInt" LIT_MAGIC_STRING_ERRORS_UL = "errors" +LIT_MAGIC_STRING_HAS_OWN_UL = "hasOwn" LIT_MAGIC_STRING_LOG10E_U = "LOG10E" LIT_MAGIC_STRING_MODULE_UL = "Module" LIT_MAGIC_STRING_NUMBER_UL = "Number" diff --git a/tests/jerry/es.next/object-hasown.js b/tests/jerry/es.next/object-hasown.js new file mode 100644 index 000000000..ed87a4e53 --- /dev/null +++ b/tests/jerry/es.next/object-hasown.js @@ -0,0 +1,56 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var obj = { "foo": 5 }; + +assert(Object.hasOwn(obj, "foo") == true); +assert(Object.hasOwn(obj, "bar") == false); + +const handler1 = {}; + +const handler2 = { + getOwnPropertyDescriptor(target, prop, receiver) { + return { configurable: true, enumerable: true, value: true }; + } +}; + +const handler3 = { + getOwnPropertyDescriptor(target, prop, receiver) { } +}; + +const proxy1 = new Proxy(obj, handler1); +const proxy2 = new Proxy(obj, handler2); +const proxy3 = new Proxy(obj, handler3); + +assert(Object.hasOwn(proxy1, "foo") == true); +assert(Object.hasOwn(proxy1, "bar") == false); + +assert(Object.hasOwn(proxy2, "foo") == true); +assert(Object.hasOwn(proxy2, "bar") == true); + +assert(Object.hasOwn(proxy3, "foo") == false); +assert(Object.hasOwn(proxy3, "bar") == false); + +try { + Object.hasOwn({}, { get toString() { throw "foo" } }); +} catch (e) { + assert(e === "foo"); +} + +try { + Object.hasOwn(undefined); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} diff --git a/tests/test262-esnext-excludelist.xml b/tests/test262-esnext-excludelist.xml index cde4a265f..e24a28d73 100644 --- a/tests/test262-esnext-excludelist.xml +++ b/tests/test262-esnext-excludelist.xml @@ -4434,69 +4434,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -