1) You're creating a new function instance for `SomeClass.method` every single time you create an instance of SomeClass. This will slow down construction.
2) `method` is an instance property, not a prototype property, and so takes up more memory for a reference per instance, plus the memory of the function instance.
3) In that function instance, you're closing over the references to `someClass` and `arg1` even though they're already available in `method` as `this` and `this.arg1`, also increasing the memory of instances.
4) Setting method will cause an unnecessary hidden-class transition.
If you really want to hide `secretArg`, use a WeakMap:
const secrets = new WeakMap();
class SomeClass {
constructor(arg1, secretArg) {
this.arg1 = arg1;
this.bar = undefined;
secrets.set(this, secretArg);
}
method(foo) {
this.bar = foo;
const secret = secrets.get(this);
secret.count++;
}
}
This will result in much lighter weight instances.In the grand scheme of all the allocation and computation taking place in my applications, these concerns are very far down the line.
Now, if you happen to be creating an application or framework that for some reason has to do a whole lot of allocating and might be meaningfully and measurably affected by such issues, then by all means use prototype "methods" when it will make a difference.
Personally, code clarity is much more important than making sure my application starts microseconds faster and allocates several bytes fewer per instance when there are only going to be ~10s of instances ever created.
Many people, especially newcomers, believe that just because their code initializes a class only N times it's being instanced exactly N times. This is false more often than not, especially in server environments.
This makes sense if it's only you working on a project, but it would be pretty confusing and weird for someone new to join.
If anything, ES6 lambdas add yet another way of interpreting `this` because while it is a function, it's not functionally scoped. Even better, a lambda is a function but `call` and `apply` are interpreted differently [1] since `this` is not bound. If you ever need to use `call` or `apply`, you'll have to know exactly how the called code is implemented to avoid bugs.
[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
SomeClass = function (arg1) {
// Hopefully do something more interesting than this, indeed. :)
this.arg1 = arg1;
};
/**
* Assigns foo to the instance variable bar.
*/
SomeClass.prototype.method = function (foo) {
// Hopefully you do something more interesting than this, too!
this.bar = foo;
};
someClass = new SomeClass();
someclass.method(foo);
Then when I need a handler for a DOM element, I bind the instance to the method: someClass = new SomeClass();
var handler = someclass.method.bind(someclass);
$('.link').click(handler); // using jQuery as easy-to-read DOM shorthand; it's not required
Or if I'm creating the handler within the class: /**
* Creates a click handler for <a class="link"> elements.
*/
SomeClass.prototype.init = function () {
var handler = this.method.bind(this);
$('.link').click(handler);
};
Over the years I've found it really easy to maintain code written like this. There's no callback hell, you don't even need Promises, and everything is easy to document. But often I find myself in an environment where I'm maintaining someone else's code, and I can't just refactor everything, so I grit my teeth and use 'that' or 'self'. I like your idea a lot better.Also, the ES2015 class keyword is syntactic sugar for the best of both worlds of the prototype pattern, combined with the private variable support of the class pattern. It does the right thing with both `this` and `super` (which is possible but tough with the prototype pattern and nearly impossible or at least crazy tough to do right with the class constructor pattern) and is as useful/important to replacing that = this/self = this antipatterns as arrow functions are.
Pervasive usage of `bind` drives me mad. It can patch over problems if you're using it locally, but if a function is being passed around, it invisibly has different behavior from a normal function with dynamic `this`. It also is quite noisey, in my opinion.
Using methods of an object to contain the sequences of an async process is handy. But it's not as flexible as promises, because it only works if the async process is self-contained. Promises are far more composable, which is important for modular processes. And with `async` functions, they allow native flow control structures to cross async boundaries. By comparison, a the methods+callbacks approach feels like programing with GOTO in BASIC.
Conventions (like prefixing with _) are great, but they can only help loosely enforce encapsulation and provide no form of real privacy.
Personally, I think sticking to one pattern makes more sense than having to switch patterns and deal with the inconsistency of that depending on your performance use-case. I personally think the prototype pattern is nicer, too.
Since this is nearly always the pattern that's followed in the class pattern, I nearly always alias `this`, if needed, to the lowercase instance name or some short identifier that semantically maps to "an instance of the class". It gets you instantly out of both the problem of "I already used `that` as an identifier, now what?" as well as providing some nice context to what you're working on if you happen to be scrolled beyond the function/constructor name.
Even if lambda expressions do fix the issue of "which that is that" it doesn't provide me any helpful context for when I'm deep in coding or reading modes.