Learn JavaScript in Construct, part 13: Onwards

17

Index

Stats

4,514 visits, 9,723 views

Tools

Translations

This tutorial hasn't been translated.

License

This tutorial is licensed under CC BY-NC 4.0. Please refer to the license text if you wish to reuse, share or remix the content contained within this tutorial.

Published on 16 Dec, 2021. Last updated 19 Jul, 2024

Odds and ends

Here are a few more details about JavaScript to mention before we finish that didn't fit in to any previous section, or were skipped over for simplicity.

Prefer const instead of let

Throughout this guide we generally used let to declare variables. However it's a good practice to actually use const for any variable that is not reassigned. The code below shows an example of where you might prefer const over let.

function getSomething()
{
	// 'x' is never reassigned, so prefer 'const'
	// over 'let' for it.
	const x = getValue();
	return x * 2;
}

Note this doesn't mean x is always the same value - it just means it never changes after it is initialised. This can be a useful thing to know when reading over more complicated functions.

The JavaScript examples in Construct's Start Page are written to prefer const, and the script editor in Construct will suggest changing variable declarations from let to const if they are never reassigned.

do-while

The do...while statement is a fairly uncommonly used variant on the standard while loop that always runs its statements at least once. Sometimes it's a useful way to write a loop, and is worth knowing about.

for-in

This guide covered 'for-of' loops, but there's another kind using the in keyword, that is mostly used in older code. It can be used to iterate the properties of an object. See for...in on MDN Web Docs for more details. However in modern code, the 'for-of' form is preferable, with Object.keys(), Object.values() or Object.entries() if you want to iterate object properties, values or both.

Legacy features

JavaScript has various old features that basically shouldn't be used any more, but you may come across them if you work with existing pieces of older code. These include:

  • var for declaring variables, which has some unusual and fairly complicated quirks, which is why let is now preferred.
  • Prior to the introduction of classes, writing object-oriented code in JavaScript typically involved modifying the prototype of functions. This can also still come in useful with classes in some more uncommon or advanced cases. You can learn more about this in Inheritance and the prototype chain.
  • Older JavaScript code sometimes also runs in "sloppy mode", i.e. non-strict mode. In Construct all code always runs in strict mode, so the way "sloppy mode" works is not relevant to code written in Construct. But once again if you need to work with older code and so need to know how it works, the differences are noted in the MDN guide on strict mode.
  • Construct always uses modules. Non-module scripts, also known as "classic" scripts, work slightly differently. Again this does not affect Construct as it always uses module scripts, but classic scripts have some small differences, notably that top-level variables are global rather than scoped to the file, and the inability to use import and export statements (but you can use dynamic imports).

Quirks

Like most programming languages, JavaScript has some quirks - unusual things that work strangely or in unexpected ways. These are best avoided. They are generally just obscurities, accidents or leftovers from poor design decisions years ago that are now too difficult to change. Don't write code that relies on them. However sometimes you have to be aware of them, if only to make sure you steer clear.

Type conversions

You can find lots of weird results when converting types. For example:

// Convert empty array to number
Number([])		// 0

// Convert empty object to number
Number({})		// NaN

// Many operators automatically convert
// to numbers, producing weird results like:
1 / []			// Infinity (1 / 0)
1 + "1"			// "11" (string)
true + true		// 2 (1 + 1)

// Operators can also automatically convert
// to strings, with weird results like:
[1] + 1			// "11" (string)
[1, 2] + [3, 4]	// "1,23,4" ("1,2" + "3,4")

Avoid writing any code that uses this! Make sure any type conversions are explicit and therefore intentional.

Non-strict equality

The non-strict equality operator == is allowed to convert types. This can produce odd results, which is a good reason to prefer strict equality === instead. Some examples of unexpected type conversions are shown below.

0 == "0"		// true
0 == false		// true
0 == []			// true
0 == [0]		// true
"1" == [1]		// true
"" == false		// true
null == undefined // true

In every case above, using strict equals === returns false instead of true, as you'd probably want as in every case the types are different. So avoid using non-strict equality and don't rely on its type conversions as they can do unexpected things.

Array indices

If you access an array at a fractional index, it will return undefined.

["😀", "👾"][0]		// "😀"
["😀", "👾"][0.5]	// undefined

The reason for this is a very strange part of JavaScript where technically the array elements are string properties that are a string of a number. Accessing arr[0.5] actually accesses a property named "0.5", i.e. arr["0.5"], which does not exist in the array; accessing a non-existent property returns undefined.

Many other programming languages avoid this by using a number for array indices that is automatically rounded. However since this does not happen in JavaScript, we have to make sure array indices are always whole numbers. Using Math.floor() on the array index is a good way to do that. For example to access a random element from an array, use arr[Math.floor(Math.random() * arr.length)], since Math.random() returns a fractional number, so it must be rounded down to a whole number.

More quirks

You'll probably come across other quirks or surprising things about JavaScript as you work more with it. Remember to try to avoid surprising parts of JavaScript - it's best to write clear code, and using obscure or accidental features of JavaScript makes your code harder to understand.

  • 5 Comments

  • Order by
Want to leave a comment? Login or Register an account!
  • Thanks for such a great series. As a game designer who's written a fair amount of code in Unreal Blueprint, C# for Unity, and Actionscript 3 for Flash, this was a great overview of the basics of JS - the best I've read. Something like this aimed at writing addons for Construct would be very helpful too, but in any case I really enjoyed this. Thank you.

  • This tutorial was long overdue. thx!

  • Hello. Why don't you recommend using for-in? I did not find any article where they preferred to use for-of or Object keys, values and entries instead of for-in.

    Here I found an article with a benchmark, which talks about the results of for-in, for-of and Object keys, values and entries. hackernoon.com/3-javascript-performance-mistakes-you-should-stop-doing-ebf84b9de951

    Object iterate For-In, average: ~240 microseconds

    Object iterate Keys For Each, average: ~294 microseconds

    Object iterate Entries For-Of, average: ~535 microseconds

    Why shouldn't I use it if it's faster?

  • Great tutorial thank you so much.

  • thanks for being with us!