Search code examples
javascriptarraysmethodsinterceptores6-proxy

JavaScript proxies : aggregate notifications after array sort


I would like to find a way to get only one notification after an array sort

Is there a way? Thank you

const callback = function () {
  console.log (...arguments)
}
const array = [2,1]
const handler = {
  set (target, prop, value, receiver) {
    callback (prop, value)
    return Reflect.set (target, prop, value, receiver)
  }
}
const proxy = new Proxy (array, handler)
proxy.sort()
// calls two times callback
// prints "0" 1 and "0" 2
// would like one notification : "array sorted"

Solution

  • You can use the .apply() trap on Array#sort() itself:

    console.config({ maximize: true });
    
    Array.prototype.sort = new Proxy(Array.prototype.sort, {
      apply(target, thisArg, argumentList) {
        const sortedThis = Reflect.apply(target, thisArg, argumentList);
        console.log('sorted');
        return sortedThis;
      }
    });
    
    console.log([2, 1].sort());
    <script src="https://gh-canon.github.io/stack-snippet-console/console.min.js"></script>

    ...or, if you want the proxy to affect your array only, you can return a custom function if the property being accessed is 'sort':

    console.config({ maximize: true });
    
    const proxy = new Proxy([2, 1], {
      get(target, property, receiver) {
        if (property === 'sort') {
          return function(comparer) {
            const originalSort = Reflect.get(target, property, receiver);
            const sortedThis = originalSort.apply(target, [comparer]);
            
            console.log('sorted');
            
            return sortedThis;
          }
        }
        
        return Reflect.get(target, property, receiver);
      }
    });
    
    console.log('.sort() works:', proxy.sort());
    console.log('.slice() is fine too:', proxy.slice(1));
    <script src="https://gh-canon.github.io/stack-snippet-console/console.min.js"></script>