Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IIFE in ES6 class literal

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?

like image 480
Tristan Tzara Avatar asked Sep 02 '16 16:09

Tristan Tzara


4 Answers

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() })()
like image 134
Frxstrem Avatar answered Nov 19 '22 23:11

Frxstrem



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'
like image 28
Juanma Menendez Avatar answered Nov 19 '22 22:11

Juanma Menendez


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.

like image 3
Denis Zatsepin Avatar answered Nov 19 '22 23:11

Denis Zatsepin


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! :-)

like image 3
Elias Hasle Avatar answered Nov 19 '22 23:11

Elias Hasle