Is it acceptable to use a function property as its own private storage?
It works, but it's weird, and the variable intended for use only inside the function isn't private, which is potentially confusing and potentially unsafe.

Functions, being objects, can have arbitrary key-value pairs assigned to them, so you can put properties on it like you're doing. It's not unheard of. Usually, this sort of thing is reserved for static properties and methods which are associated with the class/function, but don't make sense as instance methods, and are meant for use by outside consumers. For a trivial example, the below function exposes a canEat property:

function Person() {
}
Person.canEat = ['Apple', 'Banana', 'Carrot'];
Person.prototype.eat = function(food) {
  if (!Person.includes(food)) {
    throw new Error('Invalid food');
  }
  // do stuff depending on what argument is
}


Maybe it'll change over time, so users of Person can check Person.canEat before calling eat. But this is all intended for users of Person.

Another example of a useful static property on a function intended for outside use is Number.MAX_SAFE_INTEGER.

But if a property isn't meant to be used outside of the function, putting it on the function itself both sabotages the variable's privacy and is confusing (because a reader may well expect that a property accessible anywhere may be intended for use anywhere, which isn't what you mean).

If you want the function to be able to store data persistently and for itself only, you can use a closure instead. Here's one option:



const storeFunctions = (() =&gt; {
  const funcArray = [];
  return (func) =&gt; {
    if (funcArray.includes(func))
      return 'function already added';
    else {
      funcArray.push(func);
      return 'a new function is added';
    }
  }
})();

function c() { return 1 };
function d() { return 2 };
console.log(storeFunctions(c));
console.log(storeFunctions(d));
console.log(storeFunctions(c));




Professional Javascript often uses modules to organize code, in which case the IIFE is not needed - instead, have the module that defines the storeFunctions declare an array private to that module, and export the function:

const funcArray = [];
export const storeFunctions = (func) =&gt; {
  if (funcArray.includes(func))
    return 'function already added';
  else {
    funcArray.push(func);
    return 'a new function is added';
  }
};


import { storeFunctions } from './storeFunctions';
function c() {return 1};
function d() {return 2};
console.log(StoreFunctions(c));
console.log(StoreFunctions(d));
console.log(StoreFunctions(c));


The above is what I'd prefer. For any non-trivial script, modules make organizing code much easier.

Another note on your code - unless you need a collection with rearrangeable indicies, rather than using an array and iterating over it with .includes, it would probably be more appropriate to use a Set, which is a generic collection of values and whose lookup time with .has is an order of complexity faster than an array's .includes.



const storeFunctions = (() =&gt; {
  const funcSet = new Set();
  return (func) =&gt; {
    if (funcSet.has(func))
      return 'function already added';
    else {
      funcSet.add(func);
      return 'a new function is added';
    }
  }
})();

function c() { return 1 };
function d() { return 2 };
console.log(storeFunctions(c));
console.log(storeFunctions(d));
console.log(storeFunctions(c));