Starbeamrainbowlabs

Stardust
Blog


Archive

Mailing List Articles Atom Feed Comments Atom Feed Twitter Reddit Facebook

Tag Cloud

3d account algorithms announcement architecture archives arduino artificial intelligence artix assembly async audio bash batch blog bookmarklet booting c sharp c++ challenge chrome os code codepen coding conundrums coding conundrums evolved command line compilers compiling css dailyprogrammer debugging demystification distributed computing downtime electronics email embedded systems encryption es6 features event experiment external first impressions future game github github gist graphics hardware hardware meetup holiday html html5 html5 canvas infrastructure interfaces internet io.js jabber javascript js bin labs learning library linux low level lua maintenance manjaro network networking node.js operating systems performance photos php pixelbot portable privacy programming problems project projects prolog protocol protocols pseudo 3d python reddit reference release releases resource review rust secrets security series list server software sorting source code control statistics svg technical terminal textures three thing game three.js tool tutorial tutorials twitter ubuntu university update updates upgrade version control virtual reality virtualisation visual web website windows windows 10 xmpp xslt

ES6 Features 14: Modules

_This is an entry in the ES6 Features series on my blog here. Check out the full series list here

1 year and 4 months later, and we're finally seeing es6 modules start to land in a browser near you (currently Chrome, Firefox with a flag, Edge 16+, and Safari). Since I've been having to refer back to several different blog posts on the subject at once just to remind myself of a particular aspect of the new syntax, how it's used, and how it interacts with other parts of the syntax, I thought I'd blog about it here.

Before we begin, a note on enabling it in your browser. In Firefox, you need to visit about:config and set dom.moduleScripts.enabled to true instead of false (or create it if it doesn't exist). In Chrome 60, you need to go to about:flags and enable experimental javascript features or some such similar flag. Other browsers may either have it enabled by default, or require a variant on the above to get it to work.

With that, let's look at what it actually is and what it allows us to do that we couldn't before. Have you ever run into this issue before?

<script src="javascript/Vector.js"></script>
<script src="javascript/engine.js"></script>
<script src="javascript/main.js"></script>
<script src="javascript/LineSimplifier.js"></script>
<script src="javascript/Bezier.js"></script>
<script src="javascript/render.js"></script>
<!-- ... -->

It's a bit of a mess, right? Such is the problem with splitting one's code across multiple files in Javascript without a preprocessor such as Browserify or webpack.

Thankfully, it does not have to be this way! It's ES6 modules to the rescue. ES6 modules let us break our code down into discrete components that describe which other components they require. In this way, these components can be found and loaded by the browser on it's own - instead of us having to specify a whole load of <script /> tags and hope we've got them in the right order.

Let's take it from the top. Here's how you tell the browser you're loading a module and not a regular script:

<script type="module" src="./js/index.js"></script>

The above loads the file ./js/index.js as a module. In there, we cna do things like add an onload event listener to the window object to kick things off - in fact you can do practically anything you could in a normal script. Let's take a look inside an example module:

"use strict";

import Vector from "./lib/Vector.js";
import { Banana, Apple } from "./Fruits.js";

window.addEventListener("load", function(event) {
    // ......
});

Referencing another module is done with an import statement. Currently, most browsers require the ./ (or / or even a fully-qualified URL) at the beginning, and don't allow you to drop the file extension like you can in Node.JS - though this may change in the future.

I've given 2 different examples of import statements above - the first one (line #3) imports the default export and assigns it to Vector, and the second one (line #4) imports a pair of specifically named exports.

The next natural question here is how to export things so that we can import them. That's easy too:

export default Pineapple;
export { Apple, Banana, Kiwi as Coconut };
export function travel(start, finish) {
 // ....
}

As you can see, it's quite flexible actually. You can specify a default export with export default ThingName for use with the default import statement above, and you can export specifically named things - and even give them alternate names! Lastly, you can also export things as you define them - like I have with the travel() function above.

That just about covers everything. I'll leave a bunch of links below that go into more depth than I have here. I can already see the endless possibilities with this - I just wonder if anyone's built a preprocessor that concatenates all your modules into one file - whilst maintaining the ability to debug it effectively.... perhaps I'll have to do some research.

Found this useful? Let me know below! I don't currently have any analytics set up, so your comments are the only way I know if anyone's reading this :P

Sources and Further Reading

ES6 Features 13: Classes

Almost a year ago I finished a series on the new features of Ecmascript 6, the next version of Javascript. At the time there were one or two features remaining that I hadn't covered, but I didn't feel that today's browsers supported them well enough for me to write a blog post on them. Today, however, that has changed, for classes at least. In this blog post I'll explain by example how classes work in ES6.

Originally, I was against the idea of having classes in javascript. After using them for a while, I've decided to change my mind. They can bring organisation to an otherwise rather cluttered project, especially since the modules syntax hasn't yet landed.

If you've you're familiar C♯, then ES6 classes will feel a little bit familiar. Here's a simple example:


"use strict";
class Bicycle
{
    constructor(inPosition, inColour)
    {
        this.pos = inPosition;
        this.colour = inColour;
        this.wheelCount = 2;
        this.setup();
    }

    setup()
    {

    }

    update(dt)
    {
    }

    render(context)
    {
        // Do rendering stuff
    }
}

Very familiar (I hope). Classes in ES6 are defined using the class Tree { } syntax, with everything belonging to that class inside a set of curly braces, just like in C♯. Because javascript isn't a typesafe language, method declarations look a bit different. Essentially they are the same as a C♯ method declaration, just with the type names taken out.

The "use strict"; at the top is important - today's browsers don't let you use classes without it. I'll omit it in later examples for sake of simplicity, but you'll always need to remember to include it when using ES6 classes.

The constructor() method is, as you've probably guessed, the constructor of your class. Strange way of doing things, I know, but that's how it's declared. Note also that all variable initialisation is done in the constructor and not in the class body. Apparently class definitions are supposed to define an object's capabilities and not its members.

Calling a method from inside is an ES6 is easy too (see highlighted line #8), but it's important to understand what the this variable is in this context first (I could write a whole separate blog post about this). this is a special variable in javascript that holds the current context. In the case of an ES6 class, it holds the current instance of the current class. This is identical to C♯, but the difference is that you'd normally never need to use this in C♯ and it's required in ES6 - for both method access and variable access.

class Tree
{
    grow(dt, rate)
    {
        this.classMethodA(4, dt, this.someVariable);
    }

    // ...
}

White noise

Update: It turns out that ES6 does indeed support static methods (but not variables I don't think) natively via the static keyword. Here's an example:


class Tree
{
    constructor()
    {
        this.something = Tree.doComplicatedStuff();
        this.somethingElse = this.constructor.doComplicatedStuff();
    }

    static doComplicatedStuff()
    {
        // ...!
    }
}

Native static methods can be called in two ways (highlighted above). One is practically the same as the C♯ way of doing things, and the other is useful if for whatever reason you don't have the name of your own class handy.

Original sectional text

You can define static variables and methods too, although it's a little bit of a hack. Imagine I have this class:

class NoiseGenerator
{
    constructor()
    {
        // ...!
    }

    GetNoise(amount)
    {
        // ...!
    }
}
Let's pretend that we want all our noise generated with our class to use the same seedable random number generator. How about rand = new MyPRNG();? Or window.rand = new MyPRNG();? Or even this.rand = new MyPRNG()? Unfortunately, all of these methods have at least one problem with them (if you know what's wrong with them, comment down below!). Don't despair though, because we can exploit the fact that classes themselves are objects - and aren't read-only. With this knowledge, we can do something like this:

NoiseGenerator.rand = new MyPRNG(someSeed);
Remember to put the above _after_ the class definition - ES6 classes are a little bit like C++ classes in that they don't exist until the interpreter has executed them (unlike regular old functions). Then in the body of a method, you can access it with something like `NoiseGenerator.rand.nextInt(0, 10);`.

Too many classes

ES6 classes do infact support inheritance under the guise of sub classing. A good example is worth a thousand words I think:

class Vehicle
{
    constructor()
    {
        // ...
    }

    move()
    {
        console.log("Moving vehicle...");
    }

    start() { console.log("Starting..."); }
    stop() { console.log("Stopping."); }
}

class Train extends Vehicle
{
    move()
    {
        super.move();
        console.log("Moving train...");
    }
}

As demonstrated in the example above, classes can inherit from one another with the extends keyword instead of C♯'s colon. The super word replaces the functionality of C♯'s base keyword too. Other than that, there really isn't a lot more to say about inheritance in ES6 besides the fact that almost everything not described works as you'd expect it to in C♯.

That concludes my whirlwind tour of classes in ES6. If I explained in detail every little feature, you'd be here all week reading about it (and I'd be here for the better part of a month writing this post!). ES6 classes also support getters and setters, overriding the default constructor, and more.

Sources and further reading

End of ES6 Features Series

This post marks the end of my Ecmascript 6 features series of posts for now. While there are a few more topics I could cover, I don't feel that there is enough support in today's javascript engines to do them justice. At some point in the future I will come back to this series and finish off those topics that I've skipped out on this time.

Before I end this series though, I found a Javascript feature support table that you might find useful. It shows you which ES5/6/7 features are supported by which browsers and preprocessors.

Ecmascript compatibility table

That's all for now! Here's a list of all the posts that I've made so far in this series.

Ecmascript 6 Features 12: Strings

Welcome to another ES6: Features post. I think I might be getting to the end of this series soon! Anyway, this week's post is going to be on the new string related additions that have been made in Ecmascript 6. First up is a neww utility method called repeat(). As the name suggests, it duplicates a string a specified number of times:

> "e".repeat(10)
'eeeeeeeeee'
> "=-".repeat(4)
'=-=-=-=-'
> "Precarious Porcupine".repeat(3)
'Precarious PorcupinePrecarious PorcupinePrecarious Porcupine'

No more abusing new Array(length + 1).join(number)! It looks like one of those functions that should have been added a long time ago. As usual, the MDN has a polyfill that you can use.

Next up is a set of functions that make searching for things in strings much easier. There's startsWith, endsWidth and includes, and they all return a boolean:

"porcupine".startsWith("p"); // true
"porcupine".startsWith("pine", 5); // true

startsWith has an optional second argument, which lets you specify an offset from which to begin searching. endsWidth also has an optional second argument, but it lets you limit the number of characters that are searched:

"erroneous elephant".startsWith("waterfront"); // false
"erroneous elephant".endsWith("neous"); // false
"erroneous elephant".endsWith("neous", 9); // true

Lastly, there's includes. It works as you might expect it to, with the optional second argument specifying the offset from which to search:

"catastrophic crocodile".includes("croc"); // true
"catastrophic crocodile".includes("cat", 8); // false

This trio of functions should make complex string manipulation much easier to understand as you don't have to use any more complex indexOf tests anymore.

That concludes thsi ES6: Features post on strings. It seems that readability is a running theme throughout ES6. I hope that in time this makes everyone's javascript much easier to read and debug :)

Ecmascript 6 Features 11: Numbers and Math

Welcome to this week's (rather late - sorry about that! I've been out for much of the week) ES6:Features post. This week, I'll be looking at the ne wadditions to the Number and Math objects.

Firstly, there's a pair of new utility functions that have vbeen added to the Number object called Number.isNaN() and Number.isFinite(), and they can be used (as you might expect) to check to see whether a given number is not actually a number or is infinitely large respectively. Here's a few examples:

Number.isNaN(NaN); // true
Number.isNaN(359); // false
Number.isFinite(9478); // false
Number.isFinite(Infinity); // true
Number.isFinite(-Infinity); // true

The next addition is another checking function that you can use to make sure that a number is within a 'safe' range. The way that javascript interpreters or compilers work means that numbers arree manipulated with a fixed number of bits allocated to represent them. This means that there will be a limit to the size of the number that the interpreter or compiler can accurately represent. Since we have both 32 and 64 bit machines at the moment, this limit moves around from machine to machine - hence the addtion of the following function:

Number.isSafeInteger(56); // true
Number.isSafeInteger(39458634957629746293846); // false

A word of warning though: isSafeInteger, as the name implies, works only with whole numbers - so you'll probably need to run any floats through Math.floor() first, or the next new function that's been added: Math.trunc().

Math.trunc() will drop the fractional part (i.e. anything after the decimal point) of any number passed into it. This can be useful for all sorts of things, including using the function above. At first glance you might think that this function is similar to Math.floor(), but it's not. The difference is that if you feed it a negative number, it still chops the fractional part off, rather than rounding it to the next number down:

Math.trunc(-44.44); // -44
Math.floor(-44.44); // -45

After running a test on jsperf.com, I discovered that the new function is a bit slower than Math.floor and Math.ceil (108M ops/sec vs 116M ops/sec), but this is to be expected with a new function, and the difference shouldn't really be noticeable unless you are doing something really extreme :)

The last new addition is the Number.sign() function. This function is another one for convience. It returns 1 if the number is greater than 0, -1 if the number is less than 0, and 0 if the number is 0 exactly. Here are a few examples:

Number.sign(768); // 1
Number.sign(-356); // -1
Number.sign(0); // 0

That concludes this post about the new number related functions added in ES6. Most of them are for convienence, but they should improve the readability of your code a little bit. At least they aren't as confusing as Symbols! Next time I will probably be looking at the new functions added to the String object.

EcmaScript Features 10: Set

This week's ES6 feature is the Set. If you know C♯, you'll find the ES6 set to be very similar to C♯'s List class. If not, all will be explained below.

Javascript's Set is essentially a list, with a few differences here and there. You can add things to a set using the .add(thing) function, check whether a Set contains a specific value with the .has(thing) function, and get iterable object full of [key, value] pairs with the .entries() function:

> set = new Set()
Set {}
> set.add("apples")
Set { 'apples' }
> set.add("milk")
Set { 'apples', 'milk' }
> set.add("bronze pineapples")
Set { 'apples', 'milk', 'bronze pineapples' }
> set.has("milk")
true
> set.has("grapefruit")
false
> for(var item of set.entries()) { console.log(item); }
[ 'apples', 'apples' ]
[ 'milk', 'milk' ]
[ 'bronze pineapples', 'bronze pineapples' ]
undefined

Since a Set doesn't really use key value pairs, both the key and the value will be the same, unlike C♯'s List, which uses numbers as the keys for every element inside the List. This leads to an interesting situation. Suppose you try to add two identical things to a list:

> set = new Set()
Set {}
> set.add(1)
Set { 1 }
> set.add(3)
Set { 1, 3 }
> set.add(5)
Set { 1, 3, 5 }
> set.add(5)
Set { 1, 3, 5 }

You would probably expect to see the 5 appear twice in the above example, but it only appears once. What is going on here?

Since the Set uses the values you add to it as the keys when it stores the data for you, it means that if a value you give it is the same as one that you have added before, the key for the new value is the same as the key for the previous value. The result: an iterable object of unique items. You could use the new Set to ensure that your program doesn't have any duplicate entries.

Because the key and the value or any given entry are the same, it means that you have to pass a given entry to the delete function instead of it's index (which it doesn't have) in order to delete it:

> set = new Set()
Set {}
> set.add("piano")
Set { 'piano' }
> set.add("viola")
Set { 'piano', 'viola' }
> set.add("trombone")
Set { 'piano', 'viola', 'trombone' }
> set.delete("viola")
true
> set
Set { 'piano', 'trombone' }

That concludes this post on the ES6: Set. Next time, I will probably take a look at the new strign searching functions and the new number / math related functions.

Ecmascript 6 Features 8: Symbols

This week's ES6 post is about a rather strange (but useful) feature that I have only just discovered: Symbols. Before I explain to you how they work, be warned: I don't understand them fully myself yet.

Symbols are like unique keys and can be used as properties so you can use to ensure that you don't clash with any other property in an object. When creating one, you can optionally give it a 'name' so you know what it is - this can be any data type, but Symbol() will call .toString() on it first. Note that two symbols created with the same name aren't the same:

> sym1 = Symbol("starbeamrainbowlabs")
Symbol(starbeamrainbowlabs)
> sym2 = Symbol("starbeamrainbowlabs")
Symbol(starbeamrainbowlabs)
> sym1 == sym2
false

Strange, right?! This can be very useful though. You could use this to attach extra data to an object that you have been given by a library to identify it, for example, or you can use it to store something in a browser's localStorage without clashing with any other scripts running on the same domain (but this apparently doesn't persist across page reloads):

> localStorage[Symbol("bobs-rockets")] = "Some data";
"Some data"
> localStorage[Symbol("bobs-rockets")] = "Some data";
"Some data"
> localStorage
Storage { Symbol(bobs-rockets): "Some data", Symbol(bobs-rockets): "Some data" }

While this is cool, this raises the issue of retrieving the data we stored when we next load the page. If we try to create a new symbol with the same name that we used before, the browser returns undefined because the symbol we just created is not the same as the one we created the last time we loaded the page, as we discovered above.

Our next thought might be to iterate over the object and try to work out which one is ours:

> Object.keys(data).forEach(function(key) {
... console.log(`${key}: ${value}`);
... });
some-key: some-data
some-other-key: some-other-data
undefined

But weirdly, the Symbols we used don't show up! Object.keys() only returns an array of string based keys, and completely ignores the Symbols we created. This calls for a special function: Object.getOwnPropertySymbols(). This returns an array of all the Symbol based properties in an object. Then you can iterate over them like so:

> Object.getOwnPropertySymbols(data).forEach(function(key) {
... console.log(`${key.toString()}: ${value}`);
... });
Symbol(bobs-rockets): some-data
Symbol(bobs-rockets): some-data
undefined

Note the .toString() call here. If you try and convert a Symbol to a string, an exception is thrown:

TypeError: Cannot convert a Symbol value to a string

The same goes for if you accidentally use the new keyword when creating a Symbol:

> var sym = new Symbol();
TypeError: Symbol is not a constructor

There is an ever better way to recreate the same symbol across page loads though. You can use the Symbol.for() function:

> bobsSymbol = Symbol.for("bobs-rockets")
Symbol(bobs-rockets)
> bobsSymbol2 = Symbol.for("bobs-rockets")
Symbol(bobs-rockets)
> bobsSymbol == bobsSymbol2
true
> Symbol.for("bobs-rockets") == Symbol.for("bills-boosters")
false

This also allows two libraries to share the same symbol - but make sure that the string you pass to Symbol.for() is unique. This brings me onto the last thing I found out - you can reverse engineer a Symbol you obtained through Symbol.for() to work out the string used to create it with Symbol.keyFor():

> bobsSymbol = Symbol.for("bobs-rockets")
Symbol(bobs-rockets)
> Symbol.keyFor(bobsSymbol)
'bobs-rockets'

That concludes this ES6: Features post. To summarise, Symbols are unique keys that can be used to avoid conflicts in property names of objects. Every time you create one, you make a brand new Symbol that is completely different to any created before, except if Symbol.for() was used. Symbols created with Symbol.for() can be reverse-engineered to extract the string used to create it. Next time, I will probably look at well known symbols.

ES6 Features 7: Destructuring

This week's ES6 Features post is going to be on some rather new syntactic sugar, called destructuring. Please be aware that neither Node.js or io.js support this syntax, and the only browser to have a decent level of support is Firefox.

Destructuring allows you to take an array's contents and assign it's values to multiple variables at once. Whereas before you would probably do this:

> var locations = [ "Paris", "New York" ];
undefined
> var first = locations[0], second = locations[1];
undefined
> first
'Paris'
> second
'New York'

You can now do this:

> var locations = [ "Paris", "New York" ];
undefined
> var [ first, second ] = locations;
undefined
> first
'Paris'
> second
'New York'

Destructuring also supports the rest operator (...), so you can assign the rest of the values in an array to a variable too:

> var fruits = [ "orange", "apple", "banana", "kiwi", "avocado" ];
undefined
> one
"orange"
> two
"apple"
> var [one,two,three,...rest] = fruits
undefined
> three
"banana"
> rest
["kiwi", "avocado"]

Destructuring in Ecmascript 7 can also be used on objects too, allowing you to set multiple variables equal to the value of a property in any object:

> var item = { "name": "compass", "quantity": 1, "value": 250 };
undefined
> var {name, quantity, value} = item;
undefined
> name
'compass'
> quantity
1
> value
250

In order for object destructuring to work, the variable names you are declaring must have the same name as the property of the object that you want to destructure.

Destructuring also works in a function context too! If you specify an object as the only parameter to a function, you can destructure it's contents into multiple variables. This looks like a good way to simplify complex functions that have a lot of arguments.

> function test({ x: x, y: y }) { return `(${x}, ${y})`; }
undefined
> test({ x: 250, y: 50 });
'(250, 50)'

That concludes this ES6: Features post on destructuring. To summarise, destructuring is a way simplify the assigning of multiple variables at once to the values in an array. The rest operator can be used to gather up the rest of the elements left in an array. Objects can be destructured too, by both variable assignments and the arguments of a function.

Destructuring isn't generally available yet though. Just before I end this post, here's a table of who supports it:

Environment Support?
Internet Explorer 11 No
Microsoft Edge No
Chrome 44 No
Firefox 39 Yes
Opera Beta 31 No
io.js v2.3.1 No
Node.js 0.12 No
Babel Yes

Ecmascript 6 Features 6: const

We have reached the 6th post in the ES6 features series! This series of posts has to be my longest yet. This week's post is a short one about a new keyword that has been added in ES6: const. If you know any C♯, then this keywrod may already be familiar to you. It's purpose is to define a variable (called a constant) that cannot be changed or redefined.

As with normal variables, constants are function scope. When defined outside a function, they become part of the global scope. Example:

> const max_value = 64;
undefined
> max_value
64

Since constants can't be changed, setting them to a different value has no effect (but doesn't throw an error - wait, what?):

> max_value = 128;
128
> max_value
64

Redefining a constant throws an error:

> max_value
64
> const max_value = 128
TypeError: Identifier 'max_value' has already been declared

And they can't be deleted either:

> delete max_value
false
> max_value
64

It seems that you can't define a constant as a property of an object though (makes sense - then it would be a property and not a variable I suppose, though having the the syntax work like that would make things so much more readable). For that, you'll have to use Object.defineProperty() with the writable: false option.

> settings = {};
{}
> const settings.seed = 47264;
SyntaxError: Unexpected token .

Other than that, they behave like normal variables. For example you can convert a constant number to a string as normal:

> max_value.toString(2)
'1000000'
>

Though curiously, mutators on constants work correctly and change the original variable (perhaps this is a bug in io.js?):

> const y = [1,2,3]
undefined
> y
[ 1, 2, 3 ]
> y.reverse()
[ 3, 2, 1 ]
> y
[ 3, 2, 1 ]

That concludes this experimentation-heavy post on constants. To summarise:

  • Constants are variables that can't be changed (except by mutator methods)
  • You can't define a constant as the property of an object (though I wish you could)
  • Reassigning a constant has no effect (but doesn't throw an error)
  • Redefining a constant causes an error to be thrown
  • Deleting a constant has no effect and returns false

Hopefully this was useful to someone. Next time, I might take a look at some of the new additions to the Math object while I try and get my head around destructuring.

Ecmascript 6 Features 5: Spread and Rest

Unfortunately I have been rather busy this week so far, but I managed to find time to write up another post for you. This week's ES6 features are spread and rest. They go hand in hand, so I thught I would cover them both at once.

Spread

The spread operator lets you spread an array's contents out as the arguments when calling a function. It works like Function.apply, but it looks much neater :)

function multiply(a, b, c)
{
    return a * b * c;
}

var numbers = [4, 7, 2];

console.log(multiply(...numbers)); // 56

Before you might have had to do something like this:

console.log(multiply.apply(this, numbers)); // 56

Personally, I think that the new addition make a lot more sense than the old apply function, although you will still need to use Function.apply() if you want to customise the execution context of the function.

Rest

The spread operator, as you might expect, spread an array of things out to different arguments. But what if you wanted to bunch them back up again? ES6 can handle that too, through the rest operator. The rest operator allows you to bunch the rest of the arguments passed to a function into an array:

function log_adv(who, ...what)
{
    "use strict";
    var str = `[ ${new Date().toLocaleString()} ] [ ${who} ] `;
    for(let thing of what)
    {
        str += JSON.stringify(thing) + " ";
    }
    console.log(str);
}

var x = Math.random(),
    y = Math.random() * 2;

// Logs something like:
// [ 08/07/2015, 11:51:14 ] [ program ] "x is" 0.051463941344991326 "y is" 1.5026674889959395 
log_adv("program", "x is", x, "y is", y);

So there you have it! Two more new features of ES6. Next time I might look into arrow functions. Also, this Friday I will be posting about a PHP hashtag-to-title converter that I wrote for a project that I am working on for someone I know.

Art by Mythdael