skip to Main Content

I am trying to subclass JavaScript array and override ‘length’ getter and setter. This code is not working – it outputs nothing to the console because getter and setter are not called. How to fix this?

class MyArray extends Array {
  get length() {
    console.log('length getter')
    return super.length
  }

  set length(value) {
    console.log('length setter')
    super.length = value
  }
}

const arr = new MyArray()
arr.length = 1
console.log(arr.length)

2

Answers


  1. length is a non-configurable property which is created inside the Array constructor (see here). So the only way to override it is to use Proxy.

    class MyArray extends Array {
    
        constructor() {
            super()
    
            return new Proxy(this, {
                get: (target, property, receiver) => {
                    if (property === 'length') {
                        console.log('length getter')
                    }
                    
                    return Reflect.get(target, property, receiver)
                },
                set: (target, property, value, receiver) => {
                    if (property === 'length') {
                        console.log('length setter')
                    }
                    
                    return Reflect.set(target, property, value, receiver)
                },
            })
            
        }
    }
    

    Be cautious though – IT CAN DAMAGE THE PERFORMANCE OF YOUR PROGRAM.

    Login or Signup to reply.
  2. You can return an intermediate object with this as its prototype with length getter/setter.
    The only problem super doesn’t work in this scenario, I guess it’s solvable somehow but I have no clue at the moment.

    class MyArray extends Array {
    
      constructor(){
      
        super();
        const out = Object.create({}, Object.getOwnPropertyDescriptors(Object.getPrototypeOf(this)));
        Object.setPrototypeOf(out, this);
        return out;
      }
      get length() {
        console.log('length getter')
        return Object.getPrototypeOf(this).length;
      }
    
      set length(value) {
        console.log('length setter')
        Object.getPrototypeOf(this).length = value
      }
    }
    
    const arr = new MyArray()
    arr.length = 1
    console.log(arr.length)
    console.log(arr instanceof MyArray);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search