Exotic Array Objects
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
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
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
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()
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
:
- NodeList
- Possibly DOMTokenList as a subclass
- CSSRuleList
- StyleSheetList
- Possibly CSSStyleDeclaration and MediaList, as subclasses
- FileList