-1

Array method .at() is a new ES 2022 feature that takes in the index an element in an array and returns the value of it (so the element itself). I am trying to implement .at() but for some reason it keeps logging the wrong value. Can someone please help me understand why?

This is how .at works. So basically this:

const arr = ["JavaScript", "HTML", "ES2022", "CSS", "Chrome", "W3"];
console.log(arr[1]) // output: HTML

Is the same as this: console.log(arr.at(1)) //output: HTML

Here is my code implementation: It keeps outputting 'JavaScript' but I am expecting 'HTML'

const arr = ["JavaScript", "HTML", "ES2022", "CSS", "Chrome", "W3"];
Array.prototype.myAt = function (index) {

  for (let index = 0; index < this.length; index++) {
    return this[index];
  }
};

let res = arr.myAt(1);
log(res); //output: JavaScript

newcoder
  • 49
  • 8
  • 3
    ...you don't need a `for` loop at all. You can reimplement `at` in a single expression: `Array.prototype.myAt = ( idx ) => idx >= 0 ? this[idx] : this[ this.length + idx ];` – Dai Dec 01 '22 at 20:34
  • 8
    A for loop loops through all items. And you are immediately returning the first result. – cloned Dec 01 '22 at 20:34
  • 1
    @newcoder I believe that `at` allows for negative arguments to represent elements indexed relative to the end of the array. I need to look up the actual specification... but if that's the case then `return this[index];` is incorrect as it doesn't handle negative indexes (IIRC the default indexer is only defined for nonnegative indexes). – Dai Dec 01 '22 at 20:36
  • @dai yes it does handle negative arguments. you're right. Thank you so much! – newcoder Dec 01 '22 at 20:38
  • 1
    Here's the relevant section of the spec: https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.at – Dai Dec 01 '22 at 20:38
  • @Dai You [cannot use an arrow function](https://stackoverflow.com/q/31095710/1048572), though – Bergi Dec 01 '22 at 20:52
  • @Bergi You are correct, the `this` is not maintained, derp. – Dai Dec 01 '22 at 20:57
  • FYI, MDN documentation pages (like https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at) usually contain or link to "professional" polyfills, which might be worth studying. Correct polyfilling is hard, because there are lots of edge cases to take care of. – gog Dec 01 '22 at 22:47
  • @gog Ok thank you for letting me know. I'll check out the link. – newcoder Dec 02 '22 at 01:51

1 Answers1

1

You don't need a for loop at all with JS' Array type because it's an indexed type (which means it has O(1) lookup for random/arbitrary-location reads and writes) when you use its [] indexer. The .at method is just an alternative way of performing random reads (and allows you to pass it around as a function reference, which you can't do with the indexer, at least not without creating a new function with a closure).

You only need to iterate over a collection when that collection's type only supports the Iterable interface (such as when using objects representing a Generator function).

Anyway, you can reimplement at in a single expression: Array.prototype.myAt = function( idx ) { return idx >= 0 ? this[idx] : this[ this.length + idx ]; }

(I just learned you can't usefully use => to add functions to prototype as it won't capture/bind the the correct this, so using => is only okay with static-like functions that don't use this, but otherwise you need to use the long-form function() { ... } syntax).

...or more thoroughly:

/** Reimplementation of https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.at */
Array.prototype.myAt = function( index ) {

   const asInteger   = Math.floor( new Number( index ) ); // https://tc39.es/ecma262/multipage/abstract-operations.html#sec-tointegerorinfinity
   const actualIndex = asInteger >= 0 ? asInteger : ( this.length + asInteger );
   return this[ actualIndex ];
};

//

const arr = ["JavaScript", "HTML", "ES2022", "CSS", "Chrome", "W3"];
let res = arr.myAt(1);
log(res); // output: "HTML"
Dai
  • 141,631
  • 28
  • 261
  • 374