How ES6 classes work

Posted on
  • I'm just posting this up here because I had a bunch of questions in a PM and it seems what's needed is a very clear explanation about how classes work in JS.

    Hopefully this will be useful:

    ES6 Classes aren't magic - they're just a neat way of writing JavaScript functions

    Methods

    class Color {
      mymethod() {}
    }
    // is the same as
    function Color() {}
    Color.prototype.mymethod = function(){}
    

    Static Methods

    class Color {
      static mymethod() {}
    }
    // is the same as
    function Color() {}
    Color.mymethod = function(){}
    

    Using them

    // to access a METHOD, you need an instance of the class
    var color = new Color();
    color.mymethod();
    
    // to access a STATIC METHOD, you access the class directly
    Color.mymethod();
    

    You can't access a method like you'd access a static method, and you can't access a static method like you'd access a method. They're different and are accessed in different ways.

    Using this

    this isn't magic either. Looking at this code:

    class Color {
      sayhi() { 
        print(this.hello); 
      }
    }
    var color = new Color();
    color.hello = "Hello";
    

    If you use . to call a function (eg. color.sayhi()) then this is set to the bit before the ., eg color, when sayhi() is called.

    color.sayhi(); // prints 'Hello'
    
    Color.prototype.sayhi(); // prints 'undefined' because 'Color.prototype' doesn't contain 'hello'
    
    var a = color.sayhi;
    a();   // prints 'undefined' because there wasn't even a '.' - `this` is just set to the global scope
    
    var exports = {};
    exports.sayhi = color.sayhi;
    exports.sayhi(); // prints 'undefined' because 'exports' doesn't contain 'hello
    

    Similarly, if you make a static function, it won't have access to the class instance via this because in order to call the static function, you're not calling color.function() but Color.function() - and Color is the class, but color is the class instance.

    If you call another function - especially with setTimeout/setInterval this can get reset:

    class Color {
      sayhi() { 
        print(this.hello); 
        setTimeout(function() {
           print(this.hello);  // This doesn't work
        }, 1000);
      }
    }
    var color = new Color();
    color.hello = "Hello";
    color.sayhi(); // prints 'Hello', then 'undefined'
    

    There are a bunch of ways to work around it:

    // arrow functions
    class Color {
      sayhi() { 
        print(this.hello); 
        setTimeout(() => {
           print(this.hello); 
        }, 1000);
      }
    }
    

    Using modules and classes

    Right now, The Espruino IDE's minification doesn't handle classes well (it just turns them back into ES5 functions). However you can always set it just for whitespace.

    But: neither modules nor the exports variable is remotely magic

    // Module contents
    exports = "Literally anything";
    
    // Main file
    var stuff = require("mymodule");
    // stuff is now equal to "Literally anything";
    
    // This is exactly the same as
    exports = "Literally anything";
    var stuff = exports;
    // stuff is now equal to "Literally anything";
    

    When you use require("mymodule"), all Espruino does is run your module code, and then replace require("mymodule") with whatever was in the exports variable after the module finished running

    So if you do this:

    // Module contents
    exports.foo = "stuff";
    exports = function() {};
    function bob() {}
    exports.bar = bob;
    exports = "The actual thing";
    

    Then just like if you did this to any other variable, require("mymodule") will be equal to "The actual thing", not any of the stuff it was set to before.

    Exporting a class

    It's super-easy, just do:

    // Module contents
    class Color {
      method() { 
      }
      static staticmethod() { 
      }
    }
    exports = Color;
    
    // Main file
    var Color = require("mymodule");
    Color.staticmethod();
    var color = new Color();
    color.method();
    

    This is identical to just having it all in one file, without the lines exports = Color; and var Color = require("mymodule");

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

How ES6 classes work

Posted by Avatar for Gordon @Gordon

Actions