Is it not recommended writing on the function this way? Because JavaScript might release an update in the future which might hold the "error" property, then my "error" property will be overriding this JavaScript feature.
I'll take it as this being your primary query, since you've showed that you already know how to go about doing what you want to do.
This line of thinking is well-intentioned, but doesn't scale. Take for instance Object.prototype
. If we applied this line of thinking everywhere, we'd have to apply it to Object.prototype
. Every object by default has Object.prototype
in its prototype chain, unless you Object.create(null, {...})
. Do people worry every day that every single property with a generic name that they set on an object could one day overwrite a future standard property? Not that I know of.
You worry about your own choices clashing with future changes to the standard, but you should think about the other way around too: The ECMAScript standards committee wouldn't want to make a change that breaks the web (all the websites on the web that use JavaScript and have been making naming decisions for the past how many years of its existence). Go google "JavaScript smoosh" and read about the array.prototype.flatten
fiasco.
A common phrase/rule in TC39 (ECMA-International's ECMAScript standards committee) is "don't break the web":
A change to JavaScript is considered "web compatible" if it preserves the current behavior of existing websites. If it changes the behavior of existing websites, it's considered to "break the web".
The definition here is a bit fuzzy and empirical--it's always possible to construct a website which will break under any particular change or addition to JavaScript, and the key is how common the broken websites are. If too many websites break, then web browsers will refuse to ship the change.
"Don't break the web" is a shared goal of TC39 and all web standards bodies: We aim to preserve web compatibility as we evolve the language. Even if a change would be convenient for developers, it's not worth it if we hurt lots of users in the process!
Example
There was an effort to add a method Array.prototype.contains
. However, this broke many websites (reference). As a result, the method was named as Array.prototype.includes
instead.
In the end, the decision of what you do is up to you. Because of "don't break the web", I think in general, you can rest easier when choosing to do things like this.
I don't want to say this as a hard rule though, and there's a bit of nuance: If you're just adding properties to object instances at the child-most-end of prototype chains and not to prototypes of standard classes, then it's not too big of a deal, but when it comes to adding things to standard prototypes, I personally wouldn't go about doing things like this all the time- only when I see that it would increase readability significantly and over a large part of my codebase.
You can choose to do things exactly the way you have proposed, in which case you can at least mitigate the problem by following proposals to the ECMAScript standard to see if such conflict-inducing changes are planned or being discussed, or you could take a less active approach and just do a runtime check to see if the Function
prototype chain includes an error
property in it, and emit an warning message in the console if so (but don't throw an exception- then your site would break! Just log a warning and keep chugging along). And have a plan for what to do if such a conflict occurs in the future.
Or you can choose an alternate design making a compromise between your ideal and what you think is likely to avoid future problems- ex- choosing a naming scheme that is unlikely to have conflicts with new additions to the ECMAScript standard.
From what I'm hearing, you want something that is usable / convenient to write and read, but also defensive against standards changes. But if you actually only care about being defensive, you can take different approaches like not using property method functions at all (and instead use free functions like "function myError(func) {/*...*/}
"), or use Symbols instead.
Since you expressed curiosity in what JQuery is doing, based on what you have in your question post: typeof $
gives "function"
, Object.getPrototypeOf($).constructor === Function
is true
, and typeof $.ajax
gives "function"
. As far as I know, what you have proposed is currently the only way to achieving exactly what you have described that you want in your question post.
For what it's worth, any time you want to fiddle with something that has to do with changing how an object or a class of objects behaves with respect to "lower-level" JS behaviour, your first instict should be to see if there's a standard Symbol
property for it, such as Symbol.toPrimitive
, , Symbol.iterator
, and Symbol.species
. I am not aware of such a symbol property existing for turning any object into a callable object. I.e. to make something callable, you currently have have a Function
in its prototype chain.
To answer a follow-up question you posed in the comments:
can we think about achieving the same using classes? or do you think they're useless regarding this scenario?
This sounds like you are proposing a more specific case of Symbol properties (on a class (in its prototype) instead of any object). So by extension, the answer is no, I don't think they're useful here.