summaryrefslogtreecommitdiff
path: root/Libraries
diff options
context:
space:
mode:
authorLinus Groh <mail@linusgroh.de>2020-04-28 17:46:07 +0100
committerAndreas Kling <kling@serenityos.org>2020-04-28 20:15:38 +0200
commitad8abce8a539475485700acd66aa6222b95c428b (patch)
treee7a12286e034861c730a99699ff71a396db16dd9 /Libraries
parent0a0ba64383ecea92b0e8fbfbea56c54d7c0c8de3 (diff)
downloadserenity-ad8abce8a539475485700acd66aa6222b95c428b.zip
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]
Diffstat (limited to 'Libraries')
-rw-r--r--Libraries/LibJS/Runtime/ArrayPrototype.cpp12
-rw-r--r--Libraries/LibJS/Tests/Array.prototype.map.js4
2 files changed, 15 insertions, 1 deletions
diff --git a/Libraries/LibJS/Runtime/ArrayPrototype.cpp b/Libraries/LibJS/Runtime/ArrayPrototype.cpp
index 1d3c563d42..666b331ec5 100644
--- a/Libraries/LibJS/Runtime/ArrayPrototype.cpp
+++ b/Libraries/LibJS/Runtime/ArrayPrototype.cpp
@@ -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);
}
diff --git a/Libraries/LibJS/Tests/Array.prototype.map.js b/Libraries/LibJS/Tests/Array.prototype.map.js
index 148b5e3e01..c7239e23a1 100644
--- a/Libraries/LibJS/Tests/Array.prototype.map.js
+++ b/Libraries/LibJS/Tests/Array.prototype.map.js
@@ -26,6 +26,10 @@ try {
assert([1, 2, 3].map(callback).length === 3);
assert(callbackCalled === 3);
+ callbackCalled = 0;
+ assert([1, , , "foo", , undefined, , ,].map(callback).length === 8);
+ assert(callbackCalled === 3);
+
var results = [undefined, null, true, "foo", 42, {}].map((value, index) => "" + index + " -> " + value);
assert(results.length === 6);
assert(results[0] === "0 -> undefined");