ReadSpecWith.us

READ ECMASCRIPT WITH US!

Exotic Array Objects

Spec

In this episode, we shall be discussing Exotic Array Objects!

We shall be looking in the below code behaviour in accordence to the spec.

let arr = [];

arr[null] = "foo";

arr.length; //  What do you think the length is?
arr[100] = "meow";
arr.length; // what's the length now?

Array length

Links
DefineOwnProperty
OrdinaryDelete

In this episode, we will look into what happens when you set length of an Array.

let arr = [42];

//⭐️increase array.length
arr.length = 100;
arr; // [42. <99 empty items>]

//⭐decrease length
arr.length = 0;
arr; // []

When we increase array.length, it justs sets the property length to the new length. The indexes between old length to new length are not initialized or set to any value. These missing properties are referred to as holes or empty indexes.

When we descrease array.length, it tries to [[delete]] all the indexes between old length to new length in descending numerical order.

let arr = [42, 420, 840, 123];

// Set index=1 as non-configurable
Object.defineProperty(arr, "1", { value: 9, configurable: false });

// Try to delete
arr.length = 0;

// Doesn't delete all
arr; // [ 42, 9 ]
arr.length; // 2

Interestingly, the [[delete]] operation on a index property will fail if it is non-configurable. If any delete failes, it stops right there and DOESN'T try to delete remaining indexes.
So, even if you set array.length = 0, its final length might be 2 if arr[1] is non-configurable.

Array.prototype.map

Spec

In this episode, we will look into the map method on the Array prototype.

Code references from the video:

const arr = [1, 2, 3];
const doubles = arr.map((v, i, a) => v * 2); // dobubles will be [2,4,6]
// thisArgs
const foo = {
  f(v) {
    return this.g(v);
  },
  g(k) {
    return k * 2;
  },
};

[1, 2, 3].map(foo.f, foo); //[2,4,6]
// Static length
[1, 2, 3].map((v, i, a) => {
  a[10] = 100;
  return v * 2;
});
// only non-visited index value changes are respected.
[1, 2, 3].map((v, i, a) => {
  delete a[0];
  return v * 2;
}); //[ 2, 4, 6 ]

[1, 2, 3].map((v, i, a) => {
  delete a[1];
  return v * 2;
}); // [2,,6]
// holes
[null, , , undefined].map((v) => v * 2); // [0,,,NaN]

It is important to noticed that map, filter, reduce, reduceRight, some and every methods on Array has the same signature of ( callbackfn [ , thisArg ] ) and callbackfn accepts currentValue[, index[, array]].

in operator

spec

The in relational operator that returns true for own properties or the proprties in prototype chain for an object under inspection.

Code references:

1 in ["a", "b", "c"]; // true
1 in
  [][1] in // false
  ["a"]; // true
1 in
  [, , , ,][(1, 2)] in // false empty's are ignored.
  ["a", "b"]; // false
Symbol.iterator in []; // true
"x" in "xyz"; // Uncaught TypeError: Cannot use 'in' operator to search for 'x' in xyz

relative indexing with at()

spec

You might have tried to access the last element in array using arr[arr.length-1] and wondered if we had support for [-indx] and the same would apply for String and TypedArrays as -indx would be a property on them rather than the index.

Hence we have at() a proposal on stage-3 is a method on the prototype of the built-in indexable objects: Array, String, and TypedArrays objects, it also supports relative indexing from the end when passed a negative index.

Let us look into few examples:

let nums = [1, 2, 3];

nums.at(0); // 1

nums.at(-1); // 3

nums.at(100); // undefined
let name = "ECMA";

name.at(0); // "E"

name.at(-1); // "A"

name.at(100); // undefined
let unit8 = new Uint8Array([1, 2, 3]);
unit8.at(0); // 1

unit8.at(-1); // 3

unit8.at(100); // undefined

indx will be converted to 0 for NaN, null, +0, -0 or undefined

If this proposal gets adopted, the following legacy interfaces should be upgradable into ObservableArray: