Starbeamrainbowlabs

Stardust
Blog


Archive

Mailing List Articles Atom Feed Comments Atom Feed Twitter

Tag Cloud

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

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.

Ecmascript Features 4: Let and use strict

Sorry there wasn't a post in this series last week - I wasn't feeling so good. I am better now though.

This week's ES6 post will cover the let keyword. Normally in Javascript variables are declared with var and are function level. This means that once you declare a variable in a function (even if it is inside a nested block like a loop, it is available until that function's scope is removed from memory (note that a function's scope can stick around even after it completes in certain asynchronous cases).

The let keyword offers more control over the lifetime of your variables by reducing the scope of variables declared to block level. This means that once a block is removed from memory (again, this is usually when it completes - but there are certain asynchronous exceptions) the variable is destroyed.

For example, the following would work:

var foo = true;

if(foo) {
    var bar = "oranges";
}
console.log(bar);

But this wouldn't work:


var foo = true;

if(foo) {
    let bar = "oranges";
}
console.log(bar);

As of the time of writing, there are actually 2 problems with the second example. The first problem, as you have probably guessed, is that the let keyword is used inside the if block to declare a variable called bar, but the new variable is referenced outside of the if block's scope - causing a problem.

The second problem is to do with the second half of the title of this post. At the current time the above will also cause the following error in chrome based consoles:

Uncaught SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode

What is going on here? What is strict mode?

Strict mode has actually been floating around the internet for a while now (you might have heard of it) and it prevents you from doing the following by throwing an error (normally these just silently fail):

  • accidentally creating new global variables by mistyping a variable name
  • changing the type of something once created
  • assigning to a getter only property
  • adding to a fixed object
  • deleting undeletable properties
  • duplicating argument names in function definitions
  • using the with keyword
  • puts eval()ed code into it's own sandbox
  • deleting variables
  • and a whole bunch of other stuff

It's a long list, right?! Either way, turning on strict mode will help you to both catch bugs quicker and write better code to begin with. To turn it on, just put the following at the beginning of your script or function:

"use strict";

Since this is only a string, it makes it backwards compatible with older browsers, too!

That concludes this post. Next time, I will probably be taking a look at the rest and spread operators.

Art by Mythdael