Browse Source

Implement Object.prototype.isPrototypeOf (#983)

* Implement Object.prototype.isPrototypeOf

* Fix formatting

Co-authored-by: tofpie <tofpie@users.noreply.github.com>
pull/993/head
tofpie 4 years ago committed by GitHub
parent
commit
b2dba535a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 29
      boa/src/builtins/object/mod.rs
  2. 11
      boa/src/builtins/object/tests.rs
  3. 16
      boa/src/object/gcobject.rs

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

@ -51,6 +51,7 @@ impl BuiltIn for Object {
.method(Self::has_own_property, "hasOwnProperty", 0) .method(Self::has_own_property, "hasOwnProperty", 0)
.method(Self::property_is_enumerable, "propertyIsEnumerable", 0) .method(Self::property_is_enumerable, "propertyIsEnumerable", 0)
.method(Self::to_string, "toString", 0) .method(Self::to_string, "toString", 0)
.method(Self::is_prototype_of, "isPrototypeOf", 0)
.static_method(Self::create, "create", 2) .static_method(Self::create, "create", 2)
.static_method(Self::set_prototype_of, "setPrototypeOf", 2) .static_method(Self::set_prototype_of, "setPrototypeOf", 2)
.static_method(Self::get_prototype_of, "getPrototypeOf", 1) .static_method(Self::get_prototype_of, "getPrototypeOf", 1)
@ -258,6 +259,34 @@ impl Object {
Ok(obj) Ok(obj)
} }
/// `Object.prototype.isPrototypeOf( proto )`
///
/// Check whether or not an object exists within another object's prototype chain.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-object.prototype.isprototypeof
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isPrototypeOf
pub fn is_prototype_of(this: &Value, args: &[Value], context: &mut Context) -> Result<Value> {
let undefined = Value::undefined();
let mut v = args.get(0).unwrap_or(&undefined).clone();
if !v.is_object() {
return Ok(Value::Boolean(false));
}
let o = Value::from(this.to_object(context)?);
loop {
v = Self::get_prototype_of(this, &[v], context)?;
if v.is_null() {
return Ok(Value::Boolean(false));
}
if same_value(&o, &v) {
return Ok(Value::Boolean(true));
}
}
}
/// Define a property in an object /// Define a property in an object
pub fn define_property(_: &Value, args: &[Value], context: &mut Context) -> Result<Value> { pub fn define_property(_: &Value, args: &[Value], context: &mut Context) -> Result<Value> {
let obj = args.get(0).expect("Cannot get object"); let obj = args.get(0).expect("Cannot get object");

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

@ -279,3 +279,14 @@ fn object_define_properties() {
assert_eq!(forward(&mut context, "obj.p"), "42"); assert_eq!(forward(&mut context, "obj.p"), "42");
} }
#[test]
fn object_is_prototype_of() {
let mut context = Context::new();
let init = r#"
Object.prototype.isPrototypeOf(String.prototype)
"#;
assert_eq!(context.eval(init).unwrap(), Value::boolean(true));
}

16
boa/src/object/gcobject.rs

@ -198,7 +198,21 @@ impl GcObject {
// <https://tc39.es/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget> // <https://tc39.es/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget>
#[track_caller] #[track_caller]
pub fn construct(&self, args: &[Value], context: &mut Context) -> Result<Value> { pub fn construct(&self, args: &[Value], context: &mut Context) -> Result<Value> {
let this: Value = Object::create(self.get(&PROTOTYPE.into())).into(); // If the prototype of the constructor is not an object, then use the default object
// prototype as prototype for the new object
// see <https://tc39.es/ecma262/#sec-ordinarycreatefromconstructor>
// see <https://tc39.es/ecma262/#sec-getprototypefromconstructor>
let proto = self.get(&PROTOTYPE.into());
let proto = if proto.is_object() {
proto
} else {
context
.standard_objects()
.object_object()
.prototype()
.into()
};
let this: Value = Object::create(proto).into();
let this_function_object = self.clone(); let this_function_object = self.clone();
let body = if let Some(function) = self.borrow().as_function() { let body = if let Some(function) = self.borrow().as_function() {

Loading…
Cancel
Save