diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index 09af264cc6..ea07ee0c8b 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -287,19 +287,23 @@ impl Object { /// Define a property in an object pub fn define_property(_: &Value, args: &[Value], context: &mut Context) -> Result { - let obj = args.get(0).expect("Cannot get object"); - let prop = args - .get(1) - .expect("Cannot get object") - .to_property_key(context)?; - - let desc = if let Value::Object(ref object) = args.get(2).cloned().unwrap_or_default() { - object.to_property_descriptor(context)? + let object = args.get(0).cloned().unwrap_or_else(Value::undefined); + if let Some(mut object) = object.as_object() { + let key = args + .get(1) + .unwrap_or(&Value::undefined()) + .to_property_key(context)?; + let desc = args + .get(2) + .unwrap_or(&Value::undefined()) + .to_property_descriptor(context)?; + + object.define_property_or_throw(key, desc, context)?; + + Ok(object.into()) } else { - return context.throw_type_error("Property description must be an object"); - }; - obj.set_property(prop, desc); - Ok(obj.clone()) + context.throw_type_error("Object.defineProperty called on non-object") + } } /// `Object.defineProperties( proto, [propertiesObject] )` diff --git a/boa/src/object/gcobject.rs b/boa/src/object/gcobject.rs index b1129ba1a7..f3cf535417 100644 --- a/boa/src/object/gcobject.rs +++ b/boa/src/object/gcobject.rs @@ -761,7 +761,6 @@ impl GcObject { Ok(false) } } - #[inline] #[track_caller] pub fn has_own_property(&self, key: K) -> bool @@ -771,6 +770,34 @@ impl GcObject { let key = key.into(); self.get_own_property(&key).is_some() } + + /// Defines the property or throws a `TypeError` if the operation fails. + /// + /// More information: + /// - [EcmaScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-definepropertyorthrow + #[inline] + pub(crate) fn define_property_or_throw( + &mut self, + key: K, + desc: P, + context: &mut Context, + ) -> Result<()> + where + K: Into, + P: Into, + { + let key = key.into(); + let desc = desc.into(); + + let success = self.define_own_property(key.clone(), desc); + if !success { + Err(context.construct_type_error(format!("Cannot redefine property: {}", key))) + } else { + Ok(()) + } + } } impl AsRef> for GcObject {