Browse Source

LibJS: Implement Array.prototype.entries

davidot 4 years ago
parent
commit
417f752306

+ 11 - 0
Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp

@@ -64,6 +64,7 @@ void ArrayPrototype::initialize(GlobalObject& global_object)
     define_native_function(vm.names.flatMap, flat_map, 1, attr);
     define_native_function(vm.names.at, at, 1, attr);
     define_native_function(vm.names.keys, keys, 0, attr);
+    define_native_function(vm.names.entries, entries, 0, attr);
 
     // Use define_property here instead of define_native_function so that
     // Object.is(Array.prototype[Symbol.iterator], Array.prototype.values)
@@ -1264,6 +1265,16 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::values)
     return ArrayIterator::create(global_object, this_object, Object::PropertyKind::Value);
 }
 
+// 23.1.3.16 Array.prototype.entries ( ), https://tc39.es/ecma262/#sec-array.prototype.entries
+JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::entries)
+{
+    auto* this_object = vm.this_value(global_object).to_object(global_object);
+    if (!this_object)
+        return {};
+
+    return ArrayIterator::create(global_object, this_object, Object::PropertyKind::KeyAndValue);
+}
+
 // 23.1.3.16 Array.prototype.keys ( ), https://tc39.es/ecma262/#sec-array.prototype.keys
 JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::keys)
 {

+ 1 - 0
Userland/Libraries/LibJS/Runtime/ArrayPrototype.h

@@ -50,6 +50,7 @@ private:
     JS_DECLARE_NATIVE_FUNCTION(flat_map);
     JS_DECLARE_NATIVE_FUNCTION(at);
     JS_DECLARE_NATIVE_FUNCTION(keys);
+    JS_DECLARE_NATIVE_FUNCTION(entries);
 };
 
 }

+ 44 - 0
Userland/Libraries/LibJS/Tests/builtins/Array/Array.prototype.entries.js

@@ -0,0 +1,44 @@
+test("length", () => {
+    expect(Array.prototype.entries.length).toBe(0);
+});
+
+test("basic functionality", () => {
+    const a = ["a", "b", "c"];
+    const it = a.entries();
+    expect(it.next()).toEqual({ value: [0, "a"], done: false });
+    expect(it.next()).toEqual({ value: [1, "b"], done: false });
+    expect(it.next()).toEqual({ value: [2, "c"], done: false });
+    expect(it.next()).toEqual({ value: undefined, done: true });
+    expect(it.next()).toEqual({ value: undefined, done: true });
+    expect(it.next()).toEqual({ value: undefined, done: true });
+});
+
+test("works when applied to non-object", () => {
+    [true, false, 9, 2n, Symbol()].forEach(primitive => {
+        const it = [].entries.call(primitive);
+        expect(it.next()).toEqual({ value: undefined, done: true });
+        expect(it.next()).toEqual({ value: undefined, done: true });
+        expect(it.next()).toEqual({ value: undefined, done: true });
+    });
+});
+
+test("item added to array before exhaustion is accessible", () => {
+    const a = ["a", "b"];
+    const it = a.entries();
+    expect(it.next()).toEqual({ value: [0, "a"], done: false });
+    expect(it.next()).toEqual({ value: [1, "b"], done: false });
+    a.push("c");
+    expect(it.next()).toEqual({ value: [2, "c"], done: false });
+    expect(it.next()).toEqual({ value: undefined, done: true });
+    expect(it.next()).toEqual({ value: undefined, done: true });
+});
+
+test("item added to array after exhaustion is inaccessible", () => {
+    const a = ["a", "b"];
+    const it = a.entries();
+    expect(it.next()).toEqual({ value: [0, "a"], done: false });
+    expect(it.next()).toEqual({ value: [1, "b"], done: false });
+    expect(it.next()).toEqual({ value: undefined, done: true });
+    a.push("c");
+    expect(it.next()).toEqual({ value: undefined, done: true });
+});