Search code examples
javascriptmethodsbindingthisobject-literal

JavaScript Object Literal - how to replace `this` keyword for another thing


Is there any way to avoid the constant use of the this keyword to access the properties and methods of the current object?

I tried something like in Example 2, but it doesn't work at all.

Example 1:

<script>

  var fruits = {

    printApple(){ return "Apple"; },

    printBanana(){ return "Banana"; },

    printPear(){ return "Pear"; },

    printAll(){ return "All Fruits: " + this.printApple() + ", " + this.printBanana() + ", " + this.printPear(); }

  }

  alert(fruits.printAll());

</script>

Example 2:
(this script doesn't work, don't use it)

<script>

  var fruits = {

    y(){ return this.fruits; },

    printApple(){ return "Apple"; },

    printBanana(){ return "Banana"; },

    printPear(){ return "Pear"; },

    printAll(){ return "All Fruits: " + y.printApple() + ", " + y.printBanana() + ", " + y.printPear(); }

  }

  alert(fruits.printAll());

</script>

Solution

  • Seems the most idiomatic way and easy way is to use function constructors (hard objects). Actually I prefer it over prototypes and it's very good for the mixin design pattern.

    Regarding your question - no nice object literal alternative exists but you could use an anonymous constructor function:

    const obj = new function(){
      // your constructor here
    };
    

    Also tested on thousands of object against prototypes and the difference in performance is negligible for the most cases.

    One another benefit that you don't care about proper this binding anymore and can pass method refs safely, because the this binding happens in the constructor.

    function Fruits(){
    
      // add public methods here, use `self` anywhere as a safe alternative for `this`
      const self = Object.assign(this, { printAll, alertMe });
    
      function printApple() {
        return "Apple";
      }
    
      function printBanana() {
        return "Banana";
      }
    
      function printPear() {
        return "Pear";
      }
    
      function printAll() {
        return "All Fruits: " + printApple() + ", " + printBanana() + ", " + printPear();
      }
      
      function alertMe() {
    
        // use `self` if you allow to override the method in a mixin
    
        alert(self.printAll());
    
      }
    }
    
    function MixedFruits() {
    
      // call Fruits as a constructor on the current `this`
    
      Fruits.call(this);
      Object.assign(this, { printAll });
    
      function printAll(){
        return 'printAll() has been overridden!!!';
      }
    
    }
    
    const fruits = new Fruits;
    
    console.log(fruits.printAll());
    
    const mixedFruits = new MixedFruits;
    
    // we don't care about `this` when passing methods as arguments
    $base.addEventListener('click', fruits.alertMe);
    $overridden.addEventListener('click', mixedFruits.alertMe);
    <button id="$base">Fruits::alertMe()</button>
    <br/>
    <br/>
    <button id="$overridden">MixedFruits::alertMe()</button>