1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 07:47:35 +00:00

LibJS: Let Array.prototype.map() resize new array before loop

Currently we would create an empty array of size 0 and appening results
of the callback function while skipping empty values.

This is incorrect, we should be initializing a full array of the correct
size beforehand and then inserting the results while still skipping
empty values.

Wrong: new Array(5).map(() => {}) // []
Right: new Array(5).map(() => {}) // [<empty> * 5]
This commit is contained in:
Linus Groh 2020-04-28 17:46:07 +01:00 committed by Andreas Kling
parent 0a0ba64383
commit ad8abce8a5
2 changed files with 15 additions and 1 deletions

View file

@ -143,29 +143,39 @@ Value ArrayPrototype::for_each(Interpreter& interpreter)
Value ArrayPrototype::map(Interpreter& interpreter)
{
// FIXME: Make generic, i.e. work with length and numeric properties only
// This should work: Array.prototype.map.call("abc", ch => ...)
auto* array = array_from(interpreter);
if (!array)
return {};
auto* callback = callback_from_args(interpreter, "map");
if (!callback)
return {};
auto this_value = interpreter.argument(1);
auto initial_array_size = array->elements().size();
auto* new_array = Array::create(interpreter.global_object());
new_array->elements().resize(initial_array_size);
for (size_t i = 0; i < initial_array_size; ++i) {
if (i >= array->elements().size())
break;
auto value = array->elements()[i];
if (value.is_empty())
continue;
MarkedValueList arguments(interpreter.heap());
arguments.append(value);
arguments.append(Value((i32)i));
arguments.append(array);
auto result = interpreter.call(callback, this_value, move(arguments));
if (interpreter.exception())
return {};
new_array->elements().append(result);
new_array->elements()[i] = result;
}
return Value(new_array);
}