In ES5 we all could do like this:
myClass.prototype.myMethod = (function () {return function() {}})();
Am I able to do the same trick with ES6 class literals?
No, not yet at least. ES6 classes only have support for declaring methods, so anything that's not directly a method (this includes things that indirectly evaluate to a method, such as IIFE) must still be declared with the prototype.
However, ES6 classes really work the same as ES5 constructor functions do, only with a bit cleaner syntax, so you can still do this:
class MyClass {
constructor() {
/* initialize */
}
regularMethod() {
/* some stuff */
}
}
MyClass.prototype.myMethod = (function() { return function() })()
which would be equivalent to this:
function MyClass() {
/* initialize */
}
MyClass.prototype.regularMethod = function() {
/* some stuff */
}
MyClass.prototype.myMethod = (function() { return function() })()
2019 UPDATE
YES, you can do it.
You just need to create the IIFE like a "function expression" (assign it to a variable)
class MyClass {
IIFE = (() => {
let textArrayCreatedJustOnce = ['text A', 'text B', 'text C'];
console.log('Only called in object creation');
return () => {
console.log(textArrayCreatedJustOnce[1]);
}
})()
}
let myClassInstance = new MyClass(); //log: 'Only called in object creation'
myClassInstance.IIFE(); //log: 'text B'
myClassInstance.IIFE(); //log: 'text B'
myClassInstance.IIFE(); //log: 'text B'
It's possible to crate a decorator:
function iife(target, key, { value: fn, configurable, enumerable }) {
return {
configurable,
enumerable,
value: fn(),
};
}
And use it like:
class MyClass {
@iife
methodName() {
/* some stuff */
return function() {
/* real method content */
}
}
}
I use it if I need some heavy temporary variables like matrices of vectors that I don't want to crate for each method call.
The 2019 answer from @juanma-menendez is interesting, although I was left with some doubts and unanswered questions.
The first problem is that it uses arrow functions. Arrow functions handle calling context differently than ordinary function expressions. Also, they don't support recursion (as far as I know).
The second problem is that it never tries the this
keyword.
It is somewhat unclear what the calling context is in this syntactic syrup.
After some unsuccessful tries, I succeeded with the following setup in Google Chrome. This example demonstrates that both private and object attributes can be accessed from the returned method, and that it works with multiple instances:
class C {
constructor(attr) {
this.attr = attr;
}
IIFE = function() {
const privateArray = ["A", "B", "C"];
console.log("Created private array during object creation.");
return function() {
console.log("privateArray[1] = %s", privateArray[1]);
console.log("this.attr = ", this.attr);
}//.bind(this);
}.call(this);
}
var obj1 = new C("asdf");
console.log(obj1.IIFE());
console.log(obj1.IIFE());
var obj2 = new C("ghjk");
console.log(obj2.IIFE());
Outputs (undefined is the return value):
Created private array during object creation.
privateArray[1] = B
this.attr = asdf
undefined
privateArray[1] = B
this.attr = asdf
undefined
Created private array during object creation.
privateArray[1] = B
this.attr = ghjk
undefined
I must admit I don't understand why .bind(this)
was wrong. I am also a bit confused that the private array is created for each instance, and does not live solely in the prototype. I am not 100% sure this is equivalent to a prototype method made with IIFE.
Anyway, this may all possibly be a bit too high-tech for deployment, as many end users will have pre-2019 browsers. Also, I have not tested the performance. Use at own risk! :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With