diff options
author | Linus Groh <mail@linusgroh.de> | 2020-04-28 17:46:07 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-04-28 20:15:38 +0200 |
commit | ad8abce8a539475485700acd66aa6222b95c428b (patch) | |
tree | e7a12286e034861c730a99699ff71a396db16dd9 /Libraries | |
parent | 0a0ba64383ecea92b0e8fbfbea56c54d7c0c8de3 (diff) | |
download | serenity-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.cpp | 12 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/Array.prototype.map.js | 4 |
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"); |