Prefer Class Methods
ID |
javascript.prefer_class_methods |
Severity |
high |
Remediation Complexity |
medium |
Remediation Risk |
low |
Remediation Effort |
medium |
Resource |
Code Smell |
Language |
JavaScript |
Tags |
classes, code-style, legacy |
Description
Reports X.prototype.m = … where the same file declares X as a function or a class.
Reported only when the file declares the target: X resolves through the symbol table to a function declaration, a class, or a variable holding a function or class expression. Patching a type the file does not own is a different decision — a built-in is javascript.no_extend_native, and a third-party type is a monkey patch this rule has nothing useful to say about.
Only the two-hop form X.prototype.m is reported. X.prototype = {…} replaces the prototype object wholesale, dropping constructor and any inheritance already set up — a different defect, and not one a class body is the direct remedy for.
Rationale
// Bad
function Uploader(url) {
this.url = url;
}
Uploader.prototype.send = function (file) {
return post(this.url, file);
};
Uploader.prototype.cancel = function () {
this.aborted = true;
};
-
The shape of
Uploaderis whatever the assignments scattered after it happen to add, in whatever order they run. Nothing groups the members, and a reader has to search the file to learn what the type can do. -
Nothing stops a later assignment silently replacing an earlier one — there is no redeclaration error to catch the collision.
-
Private state has no spelling, so every field is public by convention only.
-
extendsandsuperare unavailable: inheritance has to be hand-wired throughObject.createand aconstructorfix-up, which is where prototype chains usually break.