Array.getter, .setter

Example:

/*Array.getter(array, getterFunc)*/
/*Array.setter(array, setterFunc)*/

function _get(index , thisArray){
	if (index >= thisArray.length) {
		console.log("Overflowed");
		return;
	}
	console.log("Getting index ", index, ", value : ", thisArray[index]);
	return thisArray[index];  // original getter is called here
}

function _set(value, index , thisArray){
	if (index > 3) {
		console.log("Overflowed");
		return;
	}
	if (index > thisArray.length) {
		console.log("No sparse array allowed");
		return;
	}
	console.log("Setting ", value, " at index ", index);
	thisArray[index] = value;
}

let myArray = [1, 2, 3];

Array.getter(myArray, _get);
Array.setter(myArray, _set);

myArray["0"] // "Getting index 0, value : 1"
myArray["1"] // "Getting index 1, value : 2"
myArray[2] // "Getting index 2, value : 3"
myArray[3] // "Overflowed"
myArray["00"] // undefined
myArray["01"] // undefined
myArray[4] = 3; //"No sparse array allowed"
myArray[3] = 4; //"Setting 4 at index 3"
myArray[4] = 4; // "Overflowed

It affects the performance, but it is useful for debugging. Right?

1 Like

Much simpler for the debugging use case would be to use Proxy and wrap your array.

3 Likes

Array getter/setter only handle a valid index property. You need not to consider other properties like length or its method push() etc. It should be more simpler and faster than using Proxy.

Being able to take an ordinary array and then add proxy like hooks to it makes the language harder to reason about and to implement. This is why Object.observe was removed. It's easier if the object specifies what needs to be intercepted at creation time like a Proxy.

Theoretically there could be a special Proxy.array that is optimized for only array access but this would likely require evidence that the performance win would be big enough. Modern JS engines are very complex and predicting what will be fast is difficult.

1 Like

This can be done even simpler:

class MyCoolArray extends Array {
  set(index, value) {
    return this[index] = value;
  }

  get(index) {
    return this[index];
  }
}

This is already done in Observable.

state.array.set(0, 1);

Anyway, my idea is just a rough idea that allows us to handle the index items.

Now, I am thinking that using some new keywords inside a class is better. In other words, it is better to create array like object. e.g. HTMLCollection .

Modern JS engines have optimized for indexed GetOwnProperty for well over a decade. Browsers use it heavily for stuff that can be both accessed by name and by index like the NamedNodeMap interface. V8 has long maintained integer indices separately from object indices for array-like objects.

It'd be an easy ask for them. And performance would improve significantly since implementors wouldn't have to stringify a property solely for the proxy handler to then, after some equality comparisons, parse back out to a number.

1 Like

I agree that an Array-specialised Proxy does sound like it'd likely be able to be more performant than the generic Proxy with an Array target. But is it common to need this? I've never personally seen it or had a need for it.

2 Likes

The use case is niche, but it does exist, and high-perf engines already necessarily expose this in their APIs to aid browsers. DOM and HTML implementations in JS in particular would greatly benefit from this. Browsers obviously can and do work around this, but the likes of JSDOM and happy-dom quite plainly can’t.

The use case being so niche is a big part of why I don’t see it as useful to grant new syntax for it, though.

The way of creating array like objects, e.g. arguments, string is good for object with small amount of item. But if the array is very large, for example, a string of length 1000, there are 1000 properties created for it. An index-value getter/setter is useful in this case.