diff --git a/boa/src/builtins/array/mod.rs b/boa/src/builtins/array/mod.rs index 62d6a4f40b..37a2571094 100644 --- a/boa/src/builtins/array/mod.rs +++ b/boa/src/builtins/array/mod.rs @@ -102,6 +102,7 @@ impl BuiltIn for Array { .method(Self::entries, "entries", 0) // Static Methods .static_method(Self::is_array, "isArray", 1) + .static_method(Self::of, "of", 0) .build(); (Self::NAME, array.into(), Self::attribute()) @@ -348,6 +349,36 @@ impl Array { } } + /// `Array.of(...arguments)` + /// + /// The Array.of method creates a new Array instance from a variable number of arguments, + /// regardless of the number or type of arguments. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// - [MDN documentation][mdn] + /// + /// [spec]: https://tc39.es/ecma262/#sec-array.of + /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/of + pub(crate) fn of(this: &Value, args: &[Value], context: &mut Context) -> Result { + let array = match this.as_object() { + Some(object) if object.is_constructable() => { + object.construct(&[args.len().into()], this, context)? + } + _ => Array::array_create(args.len() as u32, None, context), + }; + + // add properties + for (i, value) in args.iter().enumerate() { + array.set_property(i, DataDescriptor::new(value, Attribute::all())); + } + + // set length + array.set_field("length", args.len(), context)?; + + Ok(array) + } + /// `Array.prototype.concat(...arguments)` /// /// When the concat method is called with zero or more arguments, it returns an diff --git a/boa/src/builtins/array/tests.rs b/boa/src/builtins/array/tests.rs index 845669330c..fca9d69ed7 100644 --- a/boa/src/builtins/array/tests.rs +++ b/boa/src/builtins/array/tests.rs @@ -69,6 +69,54 @@ fn is_array() { } #[test] +fn of() { + let mut context = Context::new(); + assert_eq!( + context + .eval("Array.of(1, 2, 3)") + .unwrap() + .to_string(&mut context) + .unwrap(), + context + .eval("[1, 2, 3]") + .unwrap() + .to_string(&mut context) + .unwrap() + ); + assert_eq!( + context + .eval("Array.of(1, 'a', [], undefined, null)") + .unwrap() + .to_string(&mut context) + .unwrap(), + context + .eval("[1, 'a', [], undefined, null]") + .unwrap() + .to_string(&mut context) + .unwrap() + ); + assert_eq!( + context + .eval("Array.of()") + .unwrap() + .to_string(&mut context) + .unwrap(), + context.eval("[]").unwrap().to_string(&mut context).unwrap() + ); + + context + .eval(r#"let a = Array.of.call(Date, "a", undefined, 3);"#) + .unwrap(); + assert_eq!( + context.eval("a instanceof Date").unwrap(), + Value::from(true) + ); + assert_eq!(context.eval("a[0]").unwrap(), Value::from("a")); + assert_eq!(context.eval("a[1]").unwrap(), Value::undefined()); + assert_eq!(context.eval("a[2]").unwrap(), Value::from(3)); + assert_eq!(context.eval("a.length").unwrap(), Value::from(3)); +} + #[ignore] fn concat() { //TODO: array display formatter