In Python I can make an object subscriptable by implementing the __getitem__ method in a class:
class Room:
def __init__(self, furniture):
self.furniture = furniture
def __getitem__(self, index):
return self.furniture[index]
furniture = ['chair', 'TV', 'bed']
room = Room(furniture)
print(room[1]) # prints TV
As a result I can retrieve an item by only providing an index.
Can I achieve the same in Javascript? Currently I need to call the getitem method explicitly:
class Room {
constructor(furniture) {
this.furniture = furniture
}
getitem(index) {
return this.furniture[index]
}
}
let furniture = ['chair', 'TV', 'bed']
let room = new Room(furniture)
console.log(room.getitem(1))
If you want to dynamically access numeric properties from the array, you can use a Proxy for your objects with the get trap to intercept calls to numeric properties and redirect them to the getitem method:
class Room {
constructor(furniture) {
this.furniture = furniture
}
getitem(index) {
return this.furniture[index]
}
}
const handler = {
get: function(target, prop, receiver) {
const numericProp = Number(prop);
//verify the property is actually an integer
if (Number.isInteger(numericProp)) {
return target.getitem(numericProp);
} else {
//return what would be normally returned
return Reflect.get(...arguments);
}
}
}
let furniture = ['chair', 'TV', 'bed']
let room = new Room(furniture)
const proxy = new Proxy(room, handler);
console.log(proxy[0]);// chair
console.log(proxy[1]);// TV
console.log(proxy[2]);// bed
console.log(proxy[3]);// undefined
room.furniture.push("table");
console.log(proxy[3]);// table
console.log(proxy.furniture); //["chair", "TV", "bed", "table"]
You can also use the construct trap to intercept the new keyword and return already proxied objects:
class Room {
constructor(furniture) {
this.furniture = furniture
}
getitem(index) {
return this.furniture[index]
}
}
const numericGetHandler = {
get: function(target, prop, receiver) {
const numericProp = Number(prop);
//verify the property is actually an integer
if (Number.isInteger(numericProp)) {
return target.getitem(numericProp);
} else {
//return what would be normally returned
return Reflect.get(...arguments);
}
}
}
const constructProxyHandler = {
construct(target, args) {
//call the constructor normally
const instance = new target(...args);
//return a proxy
return new Proxy(instance, numericGetHandler);
}
};
const ProxyRoom = new Proxy(Room, constructProxyHandler);
let furniture = ['chair', 'TV', 'bed']
let room = new ProxyRoom(furniture)
console.log(room instanceof Room); //true
console.log(room[0]);// chair
console.log(room[1]);// TV
console.log(room[2]);// bed
console.log(room[3]);// undefined
room.furniture.push("table");
console.log(room[3]);// table
console.log(room.furniture); //["chair", "TV", "bed", "table"]
Since the Proxy is essentially transparent, if you're using modules, you can just do export new Proxy(Room, constructProxyHandler) and thus when importing, you don't need to know nor care that Proxies are involved. You can just import Room from 'room.js' and treat Room as normal.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With