0

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"

2 Answers 2

1

A viable approach which does not utilize a proxy was to use a generic implementation of an around method-modifier. The latter can be seen as a specialized case of function-wrapping.

Such a modifier accepts two functions, proceed and handler as well as a target-object as its 3 parameters. It does return a function which again is going to return the result of the handler function. The latter does get invoked within the context of the (optionally) provided target while also getting passed the proceed-function, its own handler-reference and the modified function's arguments-array.

Thus, based on such a modifier, the OP could achieve the expected behavior by modifying e.g. an array instance's sort-method like this ...

const arr = [2, 1];

// reassign the array instance's specifically modified `sort`.
arr.sort = around(arr.sort, notifyAboutFinishedTask, arr);

... where notifyAboutFinishedTask is the handler function which implements exactly what the OP is looking for ...

"... only one notification after an array sort"

... Example code ...

// implementation of `sort`-specific `around`-handler.
function notifyAboutFinishedTask(proceed, handler, args) {
  const arr = this;

  // original task.
  proceed.apply(arr, args);

  // additional notification.
  console.log('\narray sorted');
  console.log('arr ...', arr);
  console.log('arguments ...', args);
}
const arr = [2, 1];

console.log('unsorted arr ...', arr);

// reassign the array instance's specifically modified `sort`.
arr.sort = around(arr.sort, notifyAboutFinishedTask, arr);

// invoking sort twice, once with and once without sort function.
arr.sort();
arr.sort((a, b) => b - a);
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>

// implementation of an `around` modifier.
function around(proceed, handler, target) {
  return function (...args) {

    return handler.call(target ?? null, proceed, handler, args);
  };
}

</script>

Sign up to request clarification or add additional context in comments.

3 Comments

Hi, I need also to make it work within a Proxy which is also managing accessors. However your answer is very close to, even closer ... I like the link you provided, I try to summarize it here (code only) : gist.github.com/thipages/085aa96a70231b6c54c0660514bfc858. Thnak you.
Yep, I saw the git library and thanks for all your papers/loc/so. With the gist, I have just tried to have a shorter code that can be understood at a glance and adding a bit of semantics of mine (oops!).
0

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>

2 Comments

perfect. The get implementation is more suitable for my use case. Thanks
Note : ``set` will not be called which is ok !

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.