Browse Source

Implement Object.hasOwn and improve Object.prototype.hasOwnProperty (#1639)

* Implement Object.hasOwn and fix/add docs to Object.prototype.hasOwnProperty

* Tests for Object.hasOwn

* Improve tests for Object.prototype.hasOwnProperty

* Fix 'length' property descriptor bug

* Simplify Object.prototype.hasOwnProperty
pull/1646/head
Kevin Putera 3 years ago committed by GitHub
parent
commit
aaac3e9a62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 33
      boa/src/builtins/object/mod.rs
  2. 71
      boa/src/builtins/object/tests.rs

33
boa/src/builtins/object/mod.rs

@ -54,7 +54,7 @@ impl BuiltIn for Object {
.name(Self::NAME)
.length(Self::LENGTH)
.inherit(None)
.method(Self::has_own_property, "hasOwnProperty", 0)
.method(Self::has_own_property, "hasOwnProperty", 1)
.method(Self::property_is_enumerable, "propertyIsEnumerable", 0)
.method(Self::to_string, "toString", 0)
.method(Self::value_of, "valueOf", 0)
@ -87,6 +87,7 @@ impl BuiltIn for Object {
)
.static_method(Self::get_own_property_names, "getOwnPropertyNames", 1)
.static_method(Self::get_own_property_symbols, "getOwnPropertySymbols", 1)
.static_method(Self::has_own, "hasOwn", 2)
.build();
object.into()
@ -495,7 +496,7 @@ impl Object {
Ok(format!("[object {}]", tag_str).into())
}
/// `Object.prototype.hasOwnPrototype( property )`
/// `Object.prototype.hasOwnProperty( property )`
///
/// The method returns a boolean indicating whether the object has the specified property
/// as its own property (as opposed to inheriting it).
@ -511,12 +512,13 @@ impl Object {
args: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
let key = args
.get(0)
.unwrap_or(&JsValue::undefined())
.to_property_key(context)?;
// 1. Let P be ? ToPropertyKey(V).
let key = args.get_or_undefined(0).to_property_key(context)?;
// 2. Let O be ? ToObject(this value).
let object = this.to_object(context)?;
// 3. Return ? HasOwnProperty(O, P).
Ok(object.has_own_property(key, context)?.into())
}
@ -858,6 +860,25 @@ impl Object {
let o = args.get_or_undefined(0);
get_own_property_keys(o, PropertyKeyType::Symbol, context)
}
/// `Object.hasOwn( object, property )`
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-object.hasown
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn
pub fn has_own(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
// 1. Let obj be ? ToObject(O).
let obj = args.get_or_undefined(0).to_object(context)?;
// 2. Let key be ? ToPropertyKey(P).
let key = args.get_or_undefined(1).to_property_key(context)?;
// 3. Return ? HasOwnProperty(obj, key).
Ok(obj.has_own_property(key, context)?.into())
}
}
/// The abstract operation ObjectDefineProperties

71
boa/src/builtins/object/tests.rs

@ -93,30 +93,61 @@ fn object_is() {
assert_eq!(forward(&mut context, "Object.is(undefined)"), "true");
assert!(context.global_object().is_global());
}
#[test]
fn object_has_own_property() {
let mut context = Context::new();
let init = r#"
let x = { someProp: 1, undefinedProp: undefined, nullProp: null };
let scenario = r#"
let symA = Symbol('a');
let symB = Symbol('b');
let x = {
undefinedProp: undefined,
nullProp: null,
someProp: 1,
[symA]: 2,
100: 3,
};
"#;
eprintln!("{}", forward(&mut context, init));
assert_eq!(
forward(&mut context, "x.hasOwnProperty('someProp')"),
"true"
);
assert_eq!(
forward(&mut context, "x.hasOwnProperty('undefinedProp')"),
"true"
);
assert_eq!(
forward(&mut context, "x.hasOwnProperty('nullProp')"),
"true"
);
assert_eq!(
forward(&mut context, "x.hasOwnProperty('hasOwnProperty')"),
"false"
);
check_output(&[
TestAction::Execute(scenario),
TestAction::TestEq("x.hasOwnProperty('hasOwnProperty')", "false"),
TestAction::TestEq("x.hasOwnProperty('undefinedProp')", "true"),
TestAction::TestEq("x.hasOwnProperty('nullProp')", "true"),
TestAction::TestEq("x.hasOwnProperty('someProp')", "true"),
TestAction::TestEq("x.hasOwnProperty(symB)", "false"),
TestAction::TestEq("x.hasOwnProperty(symA)", "true"),
TestAction::TestEq("x.hasOwnProperty(1000)", "false"),
TestAction::TestEq("x.hasOwnProperty(100)", "true"),
]);
}
#[test]
fn object_has_own() {
let scenario = r#"
let symA = Symbol('a');
let symB = Symbol('b');
let x = {
undefinedProp: undefined,
nullProp: null,
someProp: 1,
[symA]: 2,
100: 3,
};
"#;
check_output(&[
TestAction::Execute(scenario),
TestAction::TestEq("Object.hasOwn(x, 'hasOwnProperty')", "false"),
TestAction::TestEq("Object.hasOwn(x, 'undefinedProp')", "true"),
TestAction::TestEq("Object.hasOwn(x, 'nullProp')", "true"),
TestAction::TestEq("Object.hasOwn(x, 'someProp')", "true"),
TestAction::TestEq("Object.hasOwn(x, symB)", "false"),
TestAction::TestEq("Object.hasOwn(x, symA)", "true"),
TestAction::TestEq("Object.hasOwn(x, 1000)", "false"),
TestAction::TestEq("Object.hasOwn(x, 100)", "true"),
]);
}
#[test]

Loading…
Cancel
Save