-2

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>
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
Edgaras
  • 404
  • 2
  • 16
  • 1
    this is a question, for the `example 2` how can i avoid the constant use of the `this` keyword, and replace for something more shortable. Or simply do not use. – Edgaras Jul 28 '23 at 13:59
  • Javascript is a deliberately stripped-down object language, and already complex enough for beginners. All improvements in its syntax tend towards simplification; If you have a suggestion I would be curious to read it, but I warn you a lot has been tried and things like operator overloading are ruled out. – Mister Jojo Jul 28 '23 at 14:10
  • 3
    I guess I just don't understand why using `this` is bad? – evolutionxbox Jul 28 '23 at 14:21
  • Since `fruits` is static, why not use `fruits.printApple() ...`? – evolutionxbox Jul 28 '23 at 16:15

3 Answers3

2

Since the OP's real dilemma/problem has been pictured by some of the OP's comments ...

".., because of this non beautiful and non readable code: imgur.com/WJ7pzxP" – Edgaras

... the only approach which can tackle it is locally accessing the methods from its this context and reassigning a bound version to each of the local variables.

My above comment already points into this direction ...

"@Edgaras ... In this case the OP could write ...

let { elm, Element_Create, Element_Declare /* ... */ } = this;

... for every method of this and then rebind it like ...

elm = elm.bind(this); Element_Create = Element_Create.bind(this); /* ... */

... in order to just use/invoke the method names, but each within its correct context."

Using the OP's provided, already simplified, code example the latter then should be rewritten to ...

var fruits = {

  apple: 'Apple',
  pear: 'Pear',
  banana: 'Banana',

  getApple() { return this.apple; },
  getPear() { return this.pear; },
  getBanana() { return this.banana; },

  printAll() {
    // access and assign every needed method from the `this` context.
    let { getApple, getPear, getBanana } = this;

    // reassign each method by its own bound variant each rebinding `this`.
    [getApple, getPear, getBanana] = [getApple, getPear, getBanana]
      .map(getter => getter.bind(this));

    // invoke the rebound method names without the connecting dot operator.
    return `All Fruits: ${ getApple() }, ${ getPear() }, ${ getBanana() }`;
  },
};

console.log(
  fruits.printAll()
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
1

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>
Alexander Nenashev
  • 8,775
  • 2
  • 6
  • 17
  • 1
    `const self = Object.assign(this, { printAll });` it's a nice alternative for my full project. TY for your precious help, and it's a real construtive answer/solution at my question. – Edgaras Jul 29 '23 at 22:12
0

The use of this like many languages is unavoidable. especially when you need to access properties or methods of the same object.

this keyword is special variable that every execution context gets and it automatically set by the JS engine.

Your example 2 - the script does not work because y is not defined in the global context.

      var fruits = {
    
        printApple(){ return "Apple"; },
    
        printBanana(){ return "Banana"; },
    
        printPear(){ return "Pear"; },
    
        printAll(){
          var self = this;
          return "All Fruits: " + self.printApple() + ", " + self.printBanana() + ", " + self.printPear(); 
        }
      }
    
      alert(fruits.printAll());
jagmitg
  • 4,236
  • 7
  • 25
  • 59
  • but if i had multiple `printAll()` as `printAll_1()` , `printAll_2()`, etc... i will need to declare this "var self = this;" in all of them? There's no other way? – Edgaras Jul 28 '23 at 14:09
  • 1
    @Edgaras the link I gave above, and https://stackoverflow.com/questions/4616202/self-references-in-object-literals-initializers should help. Also, what's wrong with using `this`? – evolutionxbox Jul 28 '23 at 14:18
  • @evolutionxbox, because of this non beautiful and non readable code: https://imgur.com/WJ7pzxP – Edgaras Jul 28 '23 at 14:36
  • @Edgaras ... In this case the OP could write `let { elm, Element_Create, Element_Declare /* ... */ } = this;` for every method of `this` and then rebind it like `elm = elm.bind(this); Element_Create = Element_Create.bind(this); /* ... */`, in order to just use/invoke the method names, but each within its correct context. – Peter Seliger Jul 28 '23 at 15:38