0

Using ES6/ES2015 and webpack, I am trying to wrap my head around the little monster that is the keyword this.

I have a class Edit containing a static method change(event) and within that method I am trying to make a recursive call to the method itself (depending on a given variable).

In most cases I could just call this.change(event) but here the keyword this is already occupied by the jquery object that was calling the function instead of the containing class.

The easiest solution would be to just call Edit.change(event) instead, but there must be a cleaner solution. Every programming language I have encountered so far has had some reference to its containing class built in.

I promise I have checked the docs and other threads on stackoverflow, but no one I found seems to address this particular problem.

// main.js
'use strict';

const $ = require('jquery');
const Edit = require('./Edit');

$(document).ready(() => {
    let thingsToAddToData = {
        whatToDo: // defined here depending on context
        someVariable: //defined here depending on context
        };
    $('table :input').change(thingsToAddToData, Edit.change);
}

and here the Edit class is defined

// Edit.js
class Edit {

    static change(event) {
        if(event.data.whatToDo === 'do_nothing'){
            return false;
        }
        if(event.data.whatToDo === 'do_this_important_thing'){
            // here some important stuff is done
            return true;
        }

        if(event.data.someVariable === 'special_case'){
            event.data.whatToDo = 'do_this_important_thing'

            // THIS IS THE LINE THAT GIVES ME HEADACHES
            return this.change(event);
        }
        // here some default stuff is done
    }
}

module.exports = Edit;
fridde
  • 472
  • 1
  • 5
  • 17
  • Is this your actual code? If yes: you should not use `class` at all here. Just declare a normal `function` and assign it to `module.exports.change`. – Bergi Jan 26 '19 at 13:15
  • "*Every programming language I have encountered so far has had some reference to its containing class built in.*" - what programming languages are you thinking of? – Bergi Jan 26 '19 at 13:16
  • @Bergi Maybe I was too quick to extrapolate, but my experience is with mainly PHP ("self"), Python ("self") and Java ("this"). I also know Ruby to have the "self" keyword. – fridde Jan 26 '19 at 15:55
  • @Bergi Concerning just exporting the single function: There are other static functions contained in Edit. I have tried to work with instances of classes in JS, but quickly lost track of which module was using what object of Edit. I decided that a pseudo-namespaced functional approach is better suited to my current level of competence regarding JS. This code will definitely be refactored as my understanding increases. – fridde Jan 26 '19 at 16:02
  • JavaScript has the `this` keyword - and it's quite similar to Python's `self` in the regard that you can call the method on the "wrong" self if you're doing something weird. – Bergi Jan 26 '19 at 16:04
  • And yes, the same holds if there are multiple static functions in the `class`. [Export individual functions](https://stackoverflow.com/a/29895235/1048572), using a plain object (which might be [the `module.exports` object](https://stackoverflow.com/a/5311377/1048572)) - but only use `class` syntax if you have a constructor and non-static methods. – Bergi Jan 26 '19 at 16:07

3 Answers3

1

The easiest solution would be to just call Edit.change(event) instead, but there must be a cleaner solution

No, this is indeed what you need to use to always refer to the Edit class. There's nothing messy with it, just use it.

You could also use this.change(event) if you weren't using the method as an event handler. Make sure to call it as a method:

$('table :input').change(thingsToAddToData, Edit.change.bind(Edit));
// or
$('table :input').change(thingsToAddToData, e => Edit.change(e));
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thanks for your advice! Giving me the other examples of how I "could" solve my problem gave me a new perspective on how to think about other problems in my code. – fridde Jan 26 '19 at 16:10
1

Either of the answers by @Bergi, should work (using Function.prototype.bind or () => {}). However I think your problem is more structural. Since Edit.change is an event handler it doesn't make sense to call it directly, since it is supposed to be fired through events.

I would suggest firing the event again with some parameter changes (http://api.jquery.com/trigger/):

replace Edit.change(event); with this.trigger(event);

That way there is no need for calling the handler directly, and you don't need to change the this context, thus keeping the code more transparent.

Ovenwand
  • 45
  • 8
  • If you don't want the event to be fired twice, then you don't want a recursive event handler. You simply want to split the behavior from your event handlers. Your event handler should only handle the event logic, not the actual behavior trigger by the event. – Ovenwand Jan 26 '19 at 13:38
  • I was actually not aware of the distinction between event handlers and other functions. For me any function willing to take an event object was a candidate to be an event handler. – fridde Jan 26 '19 at 16:05
  • While I am hesitant to use ```trigger()``` until I have thoroughly understood the event system and bubbling, I'll keep this on my radar for similar situations. Great tip! – fridde Jan 26 '19 at 16:13
0

Static methods operate on the class instead of instances of the class, they are called on the class. There are two ways to call static methods:

<ClassName>.methodName() 

or

<class-instance>.constructor.methodName() 

In static methods, the this keyword references the class. You can call a static method from another static method within the same class with this.

Rakesh Makluri
  • 647
  • 4
  • 10
  • 2
    No, this doesn't work. Not only are class fields experimental syntax, but also `this` would refer to the outer `this` (probably the module) not the `class`. – Bergi Jan 26 '19 at 13:20