Showing posts with label ES6. Show all posts
Showing posts with label ES6. Show all posts

Wednesday, January 4, 2017

You might (not) need a JavaScript library

JavaScript today is like:
"Yeah great, and now you need Webpack, Babel, npm, yarn, React ...".

Redux? Relax.

Developing a front end web project of today can be a bit intimidating, especially when the home base is back end development. What about all those frameworks and tools, why use them?

I am currently learning about React, and I like it. React have JSX, ES2017 and a nice logo. That is cool, but my favorite thing with React is how code is organized. A user interface is built with components: small and isolated "packages" of html & JavaScript. That is a pattern I like.

Components with vanilla JavaScript?
When learning about React patterns, I started thinking about how this could be done without using React, ES2017, Webpack or any of the other libraries and frameworks out there. Is that even possible?

Okay, but why?
I want to learn and understand the problems that are solved using a library. Also, I want to find out what problems can be solved without an npm install. One way of doing that is to write all code with plain old vanilla JavaScript, html, css and find out what pain is removed by which library. Also, I think it would be a fun challenge!

Example code
You will find all code referenced in this blog post at my GitHub page

No build step required
So, I spent some late nights coding and learning. The code in the main branch of this repo does not require any build steps or npm package downloads. The "listItem component" is made of two parts: JavaScript in a code file and an html template in a separate file. The render function will create a DOM object containing html from the template, with data that is passed in to it, and return it in a callback.

code from listItem.js:
      function render(props, done) {

        // load the template using a helper
        templates.load('/src/listItem/listItem.html', function (el) {

          // 'el' is the html template element
          el.textContent = props.data;
          el.addEventListener('click', props.onClick);

          // pass the element to be added to the DOM
          if (done) {
            done(el);
          }
        });
      }

      return {
        render: render
      };
    
The listItem.html template:
      <li class="listItem" title="the listItem component"></li>
    
This is of course a very simplistic example with a single tag html template, but I think it already highlights issues: where's the data added? To understand where data is added, we have to read & understand the contents of the render function. I think it would be nice if the data to be rendered is visible in the actual template.

Time to grow a Mustache?
A template render engine can solve that. Here's the same component, using a template engine called Mustache.js. You will find the code in a separate branch of the GitHub repo.
      function render(props, done) {
        // pass data to a modified template loader
        templates.load('/src/listItem/listItem.html', props, function (el) {
          el.addEventListener('click', props.onClick);

          if (done) {
            done(el);
          }
        });
      }
    
compare with the vanilla code

The templates helper now use Mustache to render the html from the template and the data. It is now possible to write html templates with placeholders for data like this:
      <li class="listItem" title="the listItem component">{{data}}</li>
    
code from the templates.js file:
      container.innerHTML = Mustache.render(template, data);
    
More issues?
If you look at the source code in the main branch you'll notice the JavaScript files is written with a coding style called IIFE (immediately invoked function expression). It is used to isolate code and makes it possible to write modules without using any framework. Also, every single file is added with a script tag in the html body of the main page (index.html). Some modules depend on others and have to be added in the correct order. That's not great.
      <script src="src/templates.js"></script>

      <script src="src/listItem/listItem.js"></script>
      <script src="src/list/list.js"></script>
      <script src="src/terminal/terminal.js"></script>
      <script src="src/nav/nav.js"></script>
      <script src="src/logView/logView.js"></script>

      <script src="src/app.js"></script>
    
Solution: JavaScript AMD modules
In a separate branch, I have converted all of the immediately invoked function expressions (IIFE) to AMD modules. I use Require.js that takes care of module loading and dependencies. Instead of a very long list of html script tags, there is only an entry point defined.

from the index.html file
      <script data-main="src/app" src="lib/vendor/requirejs.js"></script>
    
Here is the listItem component as an AMD module:
      define(['templates'], function (templates) {
        function render(props, done) {
          templates.load('/src/listItem/listItem.html', props, function (el) {
            el.addEventListener('click', props.onClick);

            if (done) {
              done(el);
            }
          });
        }
        return {
          render: render
        };
      });
    
compare it with the previous branch

But wait. Don't we have native modules in Javascript now?
Oh, I forgot. It is 2017 and ECMAScript 2015 was released almost two years ago. A nice module system was included in it. Finally there is a common standard in the language! I have rewritten the code to ES2017 style - with arrow functions, the const keyword and most importantly, the ES import/export feature. Now, the listItem component looks like this:
      import load from 'templates';

      export function render(props, done) {
        load('/src/listItem/listItem.html', props, (el) => {
          el.addEventListener('click', props.onClick);

          if (done) {
            done(el);
          }
        });
      }
    
compare the ES2017 code with old school JavaScript

I think the code has improved a bit. ES2017 is great, but there are trade offs to be aware of. Many browsers don't have enough support for this version of JavaScript yet. To make it work in all kinds of browsers and devices we need to introduce a build step: the code need to be compiled from ES2017 to vanilla JavaScript with Babel.

The package.json file in the project has quite a few scripts compared to the original framework-and-build-step-free version. In addition to dependencies like Mustache.js and Require.js, there is a compile step and a Babel polyfill dependency added:
      "scripts": {
        "deps:lib": "mkdir -p -v lib/vendor",
        "deps:requirejs": "cp node_modules/requirejs/require.js ...
        "deps:mustache": "cp node_modules/mustache/mustache.min.js ...

        "deps:polyfill": "cp node_modules/babel-polyfill/dist/polyfill...
        "deps": "npm run deps:lib && npm run deps:requirejs && npm run ...
        "transpile": "babel src --out-dir lib --source-maps",

        "lint": "eslint src",
        "build": "npm run lint && npm run transpile && npm run deps",
        "start": "npm run build && live-server"
      }
    
More frameworks, more problems?
When browsing the page there is now a couple of third party libraries loaded to the client, besides our own modules. This might cause a not so great experience for users with a slow connection.

Bundling & minification
While we're at it, why not add another build step that will bundle all JavaScript files to one single file? This will reduce the number of requests from the browser. With minification we also will get rid of a couple of Kilobytes. The entry point is now one bundled and minified JavaScript file.
      <script data-main="lib/bundle/main"
              src="lib/vendor/requirejs.js"></script>
    
The source code in this branch is compiled from ES2017 to browser friendly AMD modules. With Require.js, there is a tool for bundling & minification included (called R.js) and used in this branch. compare the branches

Heard about Webpack?
The scripts section of the package.json file is quite massive now and probably difficult to understand. By using Webpack, most of those build steps are no longer necessary. Webpack does a lot of things, it's like a swiss army knife (that's both good and bad, I guess).

package.json with Webpack:
      "scripts": {
        "lint": "eslint src",
        "build": "npm run lint && webpack",
        "start": "webpack-dev-server"
      }
    
compare the two branches, with bundling vs with Webpack

Where did it all go, how is that even possible? Okay, I forgot to mention Webpack.config. Sorry. Some of the build magic live in that file now.

So, did Webpack make any difference?
One nice thing with Webpack is that there is no longer any need for Require.js. Webpack will resolve ES2017 modules and convert them to plain vanilla JavaScript before the bundling & minification. Also, Webpack has a local dev server feature (with auto reloading on file change) that I like.

Add React to the mix
This is how the listItem component looks like when converted to React. The template files are gone, everything is written in the JavaScript modules using the JSX syntax. There is no longer need for a custom template loader or mustaches. Compared to the source code in the previous branch, this one has less code. I like less code.
      import React from 'react';

      function ListItem(props) {
        return <li className='listItem' title='the listItem component'
        onClick={props.onClick}>{props.data}</li>;
      }

      export default ListItem;

    
React: Before vs After

Conclusion
By experimenting with one library at a time, I have learned about the value added and also some of the trade offs that comes with using a tool or a framework. Sometimes, plain vanilla JavaScript is just enough, and sometimes a framework or library will make life easier. You might (not) need a JavaScript library.

Wednesday, March 9, 2016

JavaScript async: the future looks promising

In the beginning there was the Pyramids.

Okay, that was not exactly true. We actually had Ajax before that. With ajax, we also got callbacks. Some of the mighty callback pyramids were built and are still standing.

About one year ago, ECMAScript 2015 (aka ES 6) was released and brought native support for Promises to JavaScript. Does that mean that it now is possible to build smaller callback pyramids, instead of the mighty ones? Yes. We also have a standardized and more reliable way of writing async JavaScript code. We can write async code that behaves in a more predictable way when things go wrong.

Here's an example.

// the async consumer code, passing an url and a callback
get('path/to/my/serverside/api', (response) => {
// handle the response here
});


// the callback based ajax library that we use
function get(url, onSuccess, onFail) {
// ajax things here
// pass the result to the provided callback function
onSuccess(result);
}

What if the ajax library at some point would ... go crazy?

onSuccess(result);
onSuccess(result);
onSuccess(result);


The callback will be executed several times and it is out of our control. However, this problem can be solved by using promises. Wrap the ajax library in a promise function and consume the wrapper instead:


// the wrapper
function promiseGet(url) {
    
    return new Promise ((resolve, reject) => {
        get(url, resolve, reject);
    });
}


// consume the promisified version
promiseGet('path/to/my/serverside/api')
.then((response) => {
    // handle the response here
});

The promise will be resolved only once, even if the ajax library goes bananas.


The bus stop
This reminds me of when I was on the bus with the kids a couple of days ago. The little one wanted to press the shiny "bus-will-stop" button. When we got closer to our stop, the kid pressed the button and got the expected feedback (a "bus-will-stop" signal!). That was fun! So, he pressed the button again. But nothing happened. Naturally, he tried a couple of times more. Nothing happened.

Just like the "bus-will-stop" button, a promise is resolved only once. I think the bus driver (and passengers) appreciate the feature.


The async brain?
Async JavaScript code - with or without Promises - isn't always the easiest thing to understand. Promises does not really solve the mismatch between how our brains are wired and the flow of callbacks & thenable functions. We have learned how to write async code, and sometimes even understand it. But wouldn't it be cool if we could write something sequential like this?


var result = get('path/to/my/serverside/api');

console.log(result);


Of course, the code above won't work. 

I will try again, by using some of the magic of generators. A generator enable pause and continue functionality to a function. You can jump back and forth between a generator and the consumer code.


function* myGenerator() {

    var result = yield get('path/to/my/serverside/api');
    console.log(result);

}


That code won't work out of the box either. We need some help from a library. This library (the run function) will help us go back and forth between the generator and the consumer code, and resolve promises.


import run from 'async-runner';

run(function* myGenerator() {

    var result = yield get('path/to/my/serverside/api');
    console.log(result);

});


This will work. (here's the code used in this post)

Sequential async?
Okay, cool. It looks nice and sequential, at least when focusing on the rows within the function. But wait. Will people understand code with funky star functions and weird libraries? There has to be another way. I think the upcoming ECMAScript async & await feature can help us write easy to understand sequential code, without funky star functions or weird libraries.

Let's remove some code from our previous example:

import run from 'async-runner';

run(function* myGenerator() {

    var result = yield get('path/to/my/serverside/api');
    console.log(result);

});


And add some sweet futuristic async & await JavaScript syntax sugar:

async function myAsyncCode() {

    var result = await get('path/to/my/serverside/api');
    console.log(result);

};

With this, I think it actually is possible to use the words "readable" and "async" in the same sentence. Behind the scene, the async & await feature is a combination of Promises and Generators. I think the future of async programming looks very promising. Maybe we don't have to wait for it either. The transpiler Babel has already support for async & await today. Perhaps it is time to go back to the future?


here's the code used in this post

Tuesday, November 10, 2015

Test friendly JavaScript modules - without Dependency Injection

A while ago, I was trying to figure out how to use test driven development with ES2015 (also known as ES6 at the time). It turned out to be a nice experience, and I wrote a blog post about it: Can I test it?

However, I had some concerns about the import feature and how to deal with module dependencies. I wrote a blog post about that too: Is the ES6 import feature an anti pattern?

Recently, I have been learning Python and was surprised by the similarities with JavaScript - in coding style, philosophy and language features. I guess Python has been a source of inspiration for the new ES2015 stuff. I have quickly become a fan of Python and I think it is a very nice language.

 At first, as a Python newbie, I stumbled upon the same questions on how to unit test modules containing a bunch of import statements. Luckily, at work I am surrounded with great programmers in general, that also are experts in the Python language. With Python, the answer to my questions was both simple and obvious. Python is a dynamic language: load the dependency in the unit test, then just override it. The code under test will use the already loaded in memory module. Simple, huh? It seems to me that there is no need for c#/java like dependency injections. I guess it was my typed language mindset that had guided me to IoC and DI patterns.

What about JavaScript?
I think it is (almost) as simple! Modules and imports in JavaScript are similar to (but not exactly like) the Python way. In JavaScript, I guess it also depends on the module loader used in the current environment. I have experimented with this. My setup contain ES2015 modules and unit tests, that are transpiled with Babel to RequireJS modules, runs in a browser or with PhantomJS. With this setup, I have managed to override module dependencies with fakes from a unit test. The module under test will actually run the fake dependency, and there is no need for custom Dependency Injection.

An example: a unit test
import foo from 'modules/foo';
import bar from 'modules/bar';

const fakeMessage = 'a fake message.';

const original = bar.getMessage;
const fake = () => fakeMessage;

QUnit.module('my example tests', {
    beforeEach() {
        bar.getMessage = fake;
    },
    afterEach() {
        bar.getMessage = original;
    }
});

QUnit.test('can an imported module be mocked?', assert => {
assert.equal(foo.message(), fakeMessage);
});

And the actual code under test:
import bar from 'modules/bar';

let foo = {
    message() {
        return bar.getMessage();
    }
};


export default foo;

I would appreciate your feedback on this!

You will find unit tests, code, settings, project structure and setup at my GitHub page:
https://github.com/DavidVujic/blog/tree/master/es2015-testable-modules

Monday, July 27, 2015

Coding in the dark: ES2015 and TypeScript on an iPad

Coding in the dark
Summertime, and the Swedish weather is ... not great, but good enough! I have spent some of the vacation days here at the countryside of beautiful Värmland, Sweden, without writing any code at all. But ideas have popped up and I want to try them out. So, now I code when everybody is sleeping. The "Dark Theme" of the editor dim the bright screen light - and hopefully won't wake up the family in the middle of the night.

Direct link: Here's some example code I have written that will get you up and running with ES2015 and/or TypeScript on your iPad.




Offline coding
I really want to write code on my iPad mini, instead of using the laptop (that I also have with me, of course). With low bandwidth - sometimes no connection at all - remoting to & write code on a Cloud based VM is not an option here in the wilderness. Local and offline is better. The Coda for iOS app supports local offline files and the latest version has some really nice features. But why code on an iPad? Well ... why not! And it's convenient too, experimenting with code snippets is just a smart device away from being realized. The solutions I present here are of course useful for countryside coding on a laptop too.

ES2015 on the iPad
I decided to give ES2015 coding a try. Does it work, using an iPad and the app only? Yes, the built in web browser and file system of Coda for iOS makes it possible. When I figured out how to transpile and run the scripts in the web browser (by using Babel and the es6-module-loader library), I got carried away and thought it would be cool to also write TypeScript on the iPad. It turns out to be just as easy as the ES2015 setup.





TypeScript on the iPad
I found a nice library on GitHub by Basarat Ali Syed, that makes it possible to transpile TypeScript files to JavaScript in a web browser: basarat/typescript-script 

Here's some example code I have written that will get you up and running with ES2015 and/or TypeScript on your iPad.




Command line experimenting with the JavaScript Playground
One of the new features of the Coda app is a command line based JavaScript playground. Scripts can easily be loaded into it and the transpiler functions can be executed from the command line. I think it is a useful alternative to the web browser, and very helpful when I want to see the actual output from a transpilation.

Happy iPad coding!

Saturday, March 14, 2015

ES6 & TDD: Can I test it?

(Yes you can!)

I like the style of Test Driven Development (TDD), dead or not. I have been using TDD mainly for server side code with C# and NUnit. I think the benefits of writing unit tests for client side code is obvious. Now, with ECMAScript 6 (ES6), we have cool stuff like modules, promises, iterators ... is ES6 testable?

Interested in test driven JavaScript in general? Check out From the Streets of Test Driven Development: JavaScript.


Write, transpile, test?
To use all those cool new JavaScript features today, the source code need to be transpiled to a version that browsers support. What about the unit tests (that is also written in JavaScript)?


The unit tests can (of course) be written in old school JavaScript (ES5). But I think the context switch between the two (ES5/ES6) probably would break the flow. I would like to write both the unit test and the code in ES6. How about using Babel to transpile them both?

Check out my earlier post about some tools I use (like Babel): Sublime ES6 coding - the tools and the flow

QUnit and ES6 arrow functions
I like the simplicity and the basic TDD style of QUnit. I like the words test and assert. Jasmine and Mocha are cool to, using the behavior driven style of writing, but I prefer the classic TDD approach. Maybe it's a mindset thing? 


QUnit uses a test runner, that is where the unit tests are started. The test runner is an html file and lives in a browser (or in PhantomJS). That's the old school world. Transpiled versions of unit tests and transpiled production code will run there. There are some things to think about. QUnit doesn't identify itself as a loadable module (yet). Instead, a variable is added to the global object. By default, QUnit will run when the DOM is loaded. When used with AMD, QUnit have to be paused until the unit test modules are loaded. In this example, I have transpiled ES6 code to AMD modules (RequireJS) using Babel. The test runner is loading a single file that will import all my unit tests.

You will find unit tests, code, settings, project structure and setup on GitHub: 

ES6 and TDD

Example - the script section of the test runner html file, written in old school JavaScript:

(function () {
  'use strict';

  QUnit.config.autostart = false;
 
  require(['script/transpiled/start.js'], function () {
    QUnit.load();
    QUnit.start();

  });
}());



The contents of start.js, importing all unit test modules, written in ES6:

import {} from './modules/exampletest.js';


The unit test, written in ES6:

import foo from 'modules/foo';

QUnit.module('my example tests');

QUnit.test('will this work?', assert => {
     const expected = 'hello foo';

     assert.equal(foo.message, expected);
});


The code under test, written in ES6:

let foo = {
     message: 'hello foo'
};

export default foo;
 


The require and imports of the test runner and start.js uses relative urls. That is because I use the same base url as the production code. This enables the simple kind of imports done in the unit test. The code there is written in the same way it would in the production code.

Run with Gulp 

I use Gulp to automate a lot of things: transpiling with Babel, checking for syntax errors with JSHint and running QUnit tests with PhantomJS (i.e. no browser required). All of these will execute as soon as any ES6 file is changed in my project. By doing that, I will get instant feedback without having to interupt the flow.

Give the code a try and let me know what you think about it. What aspects am I missing? What can be improved, changed, refactored?

You will find unit tests, code, settings, project structure and setup on GitHub: 
ES6 and TDD

Thursday, March 12, 2015

Sublime ES6 coding - the tools and the flow

Sublime Text 3 and JavaScript - a nice combination
A while ago, I decided to give Sublime Text a try when learning ECMAScript 6. I mostly use Visual Studio, and with Sublime It feels like I'm on a diet! As a side effect I am also learning a little bit of Node, because many packages are based on tools installed with the Node package manager (npm). 


ECMAScript 6 (ES6)
In order to get full ES6 syntax, I have installed the babel-sublime package. Enable the package by open or create a file with a .js extension, select View -> Syntax -> Open all with current extension as ... -> Babel -> JavaScript (Babel).





JSHint
I think JSHint does the job well also with checking for errors in ES6 code. I have only found one issue - grouping exports in a module - but I can live with writing separate multiple exports until it is fixed. I think ESLint also looks very promising, but for now I will keep using JSHint.

SublimeLinter-jshint


Linting ES6?
Selecting Babel as the default syntax for .js files will actually disable the JavaScript linting. The SublimeLinter settings file need syntax mappings for Babel (the selected row in the image below). Add the row and the linting will be enabled again.  




Share the Rules
Instead of adding comments to every single .js file (like the esnext option), I use settings files (named .jshintrc). Are you on a Windows machine and can't create file names starting with a dot? Save the file with the name jshintrc, and rename it from the command prompt using the "ren" command:  

ren jshintrc .jshintrc

Transpile to old school JavaScript with Babel
Using Babel from the command line is really simple and it runs fast.
This command will create JavaScript RequireJS style modules (AMD):
babel my/es6/path --modules amd --out-dir destination/path

But running a command after each code change is an interruption, a manual step that should be automated. I use Gulp to run Babel commands and watcher to track changes in files.

Keep the flow with Gulp
With Gulp running in the background, each file change will trigger lint rules validation, ES6-to-ES5 transpilation and unit tests. An example:


var gulp = require('gulp');
var newer = require('gulp-newer');
var babel = require('gulp-babel');
var qunit = require('node-qunit-phantomjs');
var jshint = require('gulp-jshint');
 

gulp.task('lint', function () {
    return gulp.src(source)
        .pipe(jshint())
        .pipe(jshint.reporter('default')) // linting passed
        .pipe(jshint.reporter('fail')); // linting failed
});


gulp.task('transpile', function () {
    return gulp.src(source)
        .pipe(newer(destination)) // is the file changed?
        .pipe(babel({modules: 'amd'})) // run babel and pass options
        .pipe(gulp.dest(destination));
});


gulp.task('qunit', function () {
    qunit('path/to/qunit/testrunner.html', { 'verbose': false });
});


Test Driven ES6 Development with QUnit
This is a separate blog post. Stay tuned!  

Update: Here it is the post: ES6 & TDD - can I test it?

Thursday, March 5, 2015

What? Wait. Really? Oh no! (a post about ES6 classes and privacy)

ECMAScript 6 is here with lots of new features, one of them is the class keyword. Yes, we can now write classes in JavaScript. You knew that already, right? Happy, pappy? 

I guess that about half of the World population currently is doing an imaginary High Five, the other half is probably planning a revolution (or will they just write a function?). Class is a controversial thing in society.

I am not that thrilled about it, but classes are here and will be used. Heavily. JavaScript classes are however a bit different from the ones written in C# or Java. How do I write a property? Are the properties I add private or public? Most of the examples I've seen in blog posts and presentations look something like this:

class myClass {
     constructor(firstName) {
          this.firstName = firstName;
     }
}


Is "firstName" a private property? Nope. It is publicly accessible - everyone can read and change it. If you have ever used function constructors, the behavior will be familiar. Everything added to an object using the this. syntax will be public.


Is it obvious that classes will work the same way? I don't think it is. I think the word class itself implies that certain functionality should be present. Especially for programmers coming from C#, Java or any other object oriented language. In JavaScript, classes also can only contain methods. Private variables cannot be added in the class body in the same way we are used to in C#. This code will throw an error:

// will this work? (No.)
class myClass {
     let _firstName = ''; // illegal syntax
}

Almost private?

To make a property almost private, you could use the new Symbol data type to generate a property name and store it in a Module together with the class. A symbol is a unique value (like a GUID) and will (most likely) prevent properties from being overwritten by code that consumes it.

An example:

// myModule.js
let first_Name = Symbol();

// How about this, will it be private? (No.)
class myClass {
     constructor(firstName) {
          this[first_Name] = firstName;
     }

     get name() {
          return this[first_Name];
     }
}

export default myClass;


This won't make the property private, because all keys of an object (including symbols) can be accessed using the Reflect object or the getOwnPropertySymbols method of the current object.


Really private?

I have searched for and found the following solution to be good enough for creating private properties in JavaScript classes: using WeakMaps (also new in ES6). This data structure will keep track of your property names and keep them private (as long as you don't export them, of course). The data in a WeakMap is linked to the source object and will also be garbage collected when the source object is removed.

// myModule.js
const first_name = new WeakMap();

class myClass {
     constructor (firstName) {
          first_name.set(this, firstName);
     }

     get name() {
          return first_name.get(this);
     }
}

export default myClass;


By adding the current instance of the class and the actual property value to a WeakMap, we have the behavior of private variables. If this class is extended (inherited), the properties cannot be accessed directly, since the WeakMap only exists in the module. You can't have it all, I guess.

Is it worth it?

I don't know. Time will tell. Personally, I think I mostly will use simple Modules and export object literals. Or why not use a plain old Immediately Invoked Function Expression (including private variables and methods) instead of complicating things with classes?


Update:
@stevenlangbroek has shared a nice alternative solution. I think looks like a hybrid between a class and an Immediately Invoked Function Expression. Check it out! Private variables in ES6 classes

Monday, February 23, 2015

Yeah, we got classes now (ES6). You happy, pappy?

Since the beginning of time, JavaScript has been the class less society. Everyone had a function there. With ECMAScript 6, classes have now been added. Ah, man.

Wait, wait, wait! I actually like it. I believe the class keyword is good thing to JavaScript, mmkay?

There is quite a few frameworks out there that already have introduced classes (or class like solutions) to the language: Dojo, Prototype, CoffeScript, TypeScript ... They all have their own way of doing it. ECMAScript introduces a common way of how to write a class, and that itself is great. How can classes be useful in JavaScript?

I think it can simplify the structure of code, we can write functionality that is only accessible within a class. But then again, we have modules now. A module can export an object and keep code private. Why use classes?

Well, I think the benefit of writing a JavaScript class is inheritance (using the extends keyword). Inheritance can of course also be accomplished by creating literal objects extending other objects, simply by adding properties and methods to it. But the functional inheritance style looks kind of awkward sometimes. Writing a class that extends another class will probably make more sense. Especially for programmers used to write code in c#, java, Ruby or any other object oriented language.

However, I don't think consuming a class the traditional way is a good idea in JavaScript. I think it is an anti-pattern. Creating instances of classes using the new keyword spread out all over the code base? Don't do it! 


In sucks in c#, it sucks doing it in JavaScript too. Dependency Injection and IoC containers solve the "newing up classes problem" in c#. How about JavaScript?

Here's a suggestion.

Create your classes in ES6 modules. Export an already created instance (if you want a singleton like functionality), or export a "make" method that returns a new instance of the class.

By doing that, the consumer doesn't have to worry about if the code within the module is a class or an object literal.

An example:

// the foo module, exported as a singleton
class foo {
     constructor() {
          // constructor code here
     }

     myMethod () {
          // method body code here
     }
}

export default new foo();


// the foo module, exporting a "make instance" method
class foo {
     constructor() {
          // constructor code here
     }

     myMethod () {
          // method body code here
     }
}

let makeFoo = () => new foo();

export default makeFoo;



Using the first example, the consumer will get a baked and ready instance of the foo class. The second example will give the consumer the ability to get different instances, by calling the make function. The actual structure (currently a class) of the module is hidden, and not a part of the API.

What do you think about this? Let me know!






" - Happy, Pappy?"