0

I have this code that is called in an ajax callback once the data is fetched:

function onFetchCallback(data) {
    onFetchCallback.accumData ??= [];
    onFetchCallback.timeLine ??= [];
    onFetchCallback.tempValues1 ??= [];
    onFetchCallback.tempValues2 ??= [];
    onFetchCallback.char;
    const hasNulls = data.includes(null);
    if (!hasNulls) {
        //push values into different arrays
    } else {
        //push the rest of no nulls if there is any...
    }
}

I dont find this clean, bacause I am checking if the arrays that accumulate the data are initialized for every callback call. I think it woull be better to have the callback function initialized, so that the arrays are created, and then call the functions that will store the data in the arrays.

So I did:

function onFetchCallback() {
    function init() {
        onFetchCallback.accumData ??= [];
        onFetchCallback.timeLine ??= [];
        onFetchCallback.tempValues1 ??= [];
        onFetchCallback.tempValues2 ??= [];
        onFetchCallback.char;
    }

    function store(data) {
        const hasNulls = data.includes(null);
        if (!hasNulls) {
            //push values into different arrays
        } else {
            //push the rest of no nulls if there is any...
        }
    }
    
    onFetchCallback.init = init;
    onFetchCallback.store = store;
}

So then when I need to use my callback I do:

onFetchCallback();
onFetchCallback.init();
myWhateverFunc(onFetchCallback.store);

Being myWhateverFunc the one calling the callback:

function myWhateverFunc(callback) {
    $.ajax({ 
        //whatever
    })
    .done(function (data) {
        callback(data); //CALL
    });
}

This works and I find it super javasScriptic so I do it all the time. Meaning the onFetchCallback initialization + other methods call to handle the function members. I do not know js in depth so I would like to know of there are any flaws with this pattern, or if there is any other better/cooler/javaScriptStylish way to do this.

rustyBucketBay
  • 4,320
  • 3
  • 17
  • 47
  • The really weird thing is that you're storing properties on `onFetchCallback` itself, and that `onFetchCallback()` doesn't actually do anything but create two functions. Instead, create an object! – Bergi Sep 05 '21 at 21:17

1 Answers1

1

The pattern you're using has a lot of resemblence with the function constructor which is more commonly used in JavaScript.

An implementation of your code in the function constructor pattern would like like this:

function FetchCallback() {
  this.accumData = [];
  this.timeLine = [];
  this.tempValues1 = [];
  this.tempValues2 = [];
  this.char;
}

FetchCallback.prototype.store = function(data) {
  const hasNulls = data.includes(null);
  if (!hasNulls) {
    // push values into different arrays
  } else {
    // push the rest of no nulls if there is any...
  }
};

It enables you to create an object with properties and methods which are predefined. This removes the hassle of repetition when you need multiple instances of this same object.

To use the constructor you'll need to create a new instance with the new keyword. This will return an object with all the properties and methods set.

const fetchCallback = new FetchCallback();

// Note the .bind() method!
myWhateverFunc(fetchCallback.store.bind(fetchCallback));

Edit

You'll need to specifically set the value of this to the created instance that is stored in fetchCallback. You can do this with the bind() method. This methods explicitly tells that this should refer to a specific object.

The reason to do this is that whenever you pass the store method as the callback to the myWhateverFunc, it loses it's context with the FetchCallback function. You can read more about this in this post


The main difference between this and your code is that here the FetchCallback function will be unaltered, where your function is reassigned every time you call onFetchCallback() and onFetchCallback.init(). The constructor pattern will result in more predictable behavior, albeit that the this keyword has a learning curve.

Emiel Zuurbier
  • 19,095
  • 3
  • 17
  • 32
  • thanks a lot for your anwer. Lots of insights there!. What if `FetchCallback` is defined in the window context. `this` will be the window and not the function. That is why I did for example the variables of `onFetchCallback` static with `onFetchCallback.variableName`. That produces the variables be defined at the window context, which I don't like much – rustyBucketBay Sep 05 '21 at 20:34
  • I don't think I understand. The example above can be defined in the *window* context. `this` will point to the object returned by `new FetchCallback();`. It's because `this` is now in the context of the `FetchCallback` function and not the `window` object anymore. It also means that you can use `this` in the `store` function, and it will point to the same object. – Emiel Zuurbier Sep 05 '21 at 20:41
  • very true. Thanks a lot! – rustyBucketBay Sep 05 '21 at 20:46
  • The `myWhateverFunc(fetchCallback.store);` in your example doesn't work [because it doesn't bind the correct `this` value](https://stackoverflow.com/q/20279484/1048572) – Bergi Sep 05 '21 at 21:16
  • @Bergi, thanks for pointing that out. Modified the answer. – Emiel Zuurbier Sep 06 '21 at 08:11
  • I was not aware of that. Thanks for the explanation, it's clear. – rustyBucketBay Sep 06 '21 at 19:10