Gamasutra is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.

Gamasutra: The Art & Business of Making Gamesspacer
Making the Move to HTML5, Part 1
View All     RSS
July 19, 2019
arrowPress Releases
July 19, 2019
Games Press
View All     RSS

If you enjoy reading this site, you might also want to check out these UBM Tech sites:


Making the Move to HTML5, Part 1

February 7, 2013 Article Start Previous Page 2 of 3 Next

JavaScript for Game Development

Only one general-purpose programming language can be used in the browser: JavaScript. It's also known by its official name: ECMAScript. This is not intended to be a guide or introduction to the language, but we have highlighted some aspects that stood out to us or had unexpected performance implications when approaching JavaScript from a C/C++ background.

Particularly when moving a big project from C/C++ to JavaScript for the first time, developers will likely face some challenges. The JavaScript syntax resembles C, but the language has more in common with functional languages like Lisp; it has closures and first-class functions.

We found closures to be very powerful, making asynchronous programming much easier and clearer. However, subtle errors can occur if developers are not fully aware of their behavior.

For example, quite a common mistake is to create closures inside a loop, referencing variables that change during the execution of that loop. This can lead to confusing behavior since variables referenced by a closure contain the value at the point the closure is executed, not at the point of its creation.

JavaScript has first-class functions, meaning that functions can be passed as parameters, returned from other functions, assigned to variables and stored in dictionaries. Strings can be compiled at runtime into functions, although this is not recommended for security reasons as the string could come from an unknown source and could compromise other parts of the code.

The language has object-oriented features, but there are no classes. JavaScript has constructors and prototype-oriented inheritance. Objects behave like key-value dictionaries, able to optimally store and retrieve anything by name. We found that trying to access values by the wrong name was a common error, usually a typo in the code that stores or retrieves the data.

Objects can be assigned as prototypes of other objects. If a property is not found on an object then the runtime will check the prototype object, and so on. As functions can be stored on objects and objects can share prototypes, the prototype mechanism allows methods and code reuse in a familiar way. Functions also behave as objects, and can be used to store and retrieve properties by name.

JavaScript objects do not have destructors. The JavaScript runtime schedules their destruction once there are no remaining references to them, and JavaScript code does not receive any notification when that happens. We found it non-trivial to find memory leaks in JavaScript code (that is, hanging references to objects which are in turn never garbage collected). Some JavaScript profilers provide object counts on their heap snapshots, which does help, but they require that objects be created from non-literal constructors, using the new operator, in order to differentiate between them. Some profilers also provide reference tracking in their heap snapshots which helps to identify why a given object has not been garbage collected.

As a best practice, we recommend establishing a clear and well-defined policy of object ownership. This makes it easier to point to the code that is responsible for maintaining (and releasing) the reference to a given object.

JavaScript does not have static types, so variables are allowed to have different types over the life of the program and some automatic conversions will happen if different types are used in the same operation. For example, adding numbers to strings will result in a string concatenation of the number converted to a string. This can result in errors that are very hard to find and can have performance implications.

Another subtle point and possible source of bugs are the JavaScript bitwise operations, which convert parameters to signed 32-bit integers with big-endian order and in two's complement format. For example, the following two statements are true:

(0x80 << 24) !== 0x80000000

(0x80 << 24) === -2147483648

Both would be false if unsigned integers were used. Note the use of the triple-equal operator, because it does not perform type conversion if the operands have different types. In contrast, the double-equal operator does perform type conversion and could hide errors in the code.

Although JavaScript variables can have Boolean values, every other basic type can be used on a conditional expression, with the following values being equivalent to false: null, undefined, the empty string, the number zero, the number NaN.

JavaScript does not have block scope; it has a global scope and function scope. Variables can be created anywhere in a function, and will be accessible everywhere, as if they were declared at the top of the function. This will confuse experienced C++ developers who are new to JavaScript.

Exceptions are supported in JavaScript, but the language does not support an exception hierarchy. The throw operator can be used on anything; an object, a number, a string, and it is caught by the first try / catch surrounding the code. There is no way to catch only objects of a specific type.

The language has evolved considerably from its origin and some features are not entirely standardized across browsers. Any recently added feature should be checked for before use. For example, the ability to define getters and setters for object properties with Object.defineProperty has, for us, become one of the most useful features added recently, however we need to provide extra code paths for when support does not exist. In some cases testing for the existence of a function is enough to check for a supported feature, as in the case of Object.defineProperty. In other cases, the code must try to actually use the feature inside a try / catch block and check whether an exception was raised.

We found JavaScript to be a powerful language because of its dynamic nature and functional features, but also a complicated language for big projects. With multiple developers working in parallel on a code base of hundreds of thousands of lines of code, mistakes will happen infuriatingly often without discipline and the right development tools.

At Turbulenz, we try to minimize development mistakes by employing a development process focused on code quality: strict coding standards, frequent code reviews and automatic unit testing. We also routinely use static analysis tools to check our code for common mistakes. So far we have not found analysis tools with the same level of inspection as those available for C and C++, but the following tools have been helpful in that they do catch a fairly large class of bugs, and they do improve over time: Closure Linter, JSHint, and JSLint.

When a new software engineer joins Turbulenz, they receive a copy of JavaScript: The Good Parts by Douglas Crockford. We consider this book a very good introduction to JavaScript, explaining common mistakes and good patterns.

Conversion Tools

Some developers may be interested in the translation tools available for converting other languages to JavaScript. They allow development in one language -- such as one with static typing in order to minimize runtime errors -- which is then converted to JavaScript.

Some of the more popular tools include haXe, Dart and Emscripten. The TypeScript project is a relatively recent addition that extends JavaScript to allow type information to be specified. This is particularly interesting since, as well as providing advantages in terms of error checking and development tools, TypeScript is "backwards compatible" with JavaScript.

We would encourage anyone considering using these tools to make sure they fully understand the implications. Automatically generated JavaScript code may provide suboptimal performance or a substantial size increase over hand-written JavaScript code. What works well in one environment may fail in a different one, requiring multiple code paths. Debugging problems and tracing back to the original offending code may prove difficult, and in some cases fixes may require tweaking the original source code to "trick" the compiler into generating safe JavaScript. Support for specific browser features may not exist, which will also limit what can be achieved.

However, these tools do have some interesting properties (such as the ability to turn C++ code into JavaScript that does essentially no garbage collection), and they are continually evolving and improving. It makes sense to be aware of them as an option, and to monitor their development.


Editors for static typed languages can provide a lot of functionality that is harder to provide for dynamic languages.

Good editors supporting JavaScript usually provide:

  • Syntax highlighting
  • Auto-completion suggestions for:
    • Default global objects.
    • Well-known external libraries like jQuery.
    • Variables and functions defined within the current function.
    • Global variables and global functions defined within the current file.
  • Refactoring at the current file level.
  • Integration with JSLint or JSHint.

Features such as auto-completion for custom objects, global variables from other files etc. are still lacking for dynamic languages. Some editors are starting to parse and execute all the JavaScript code in the current project in their own JavaScript engines to better judge the availability of variables and properties at the current point in the code. However these editors will frequently generate incorrect or incomplete suggestions. Writing your code in specific ways may help the editor with its suggestions, for example by initializing all the properties in the constructor. In this case the editor may be able to track which constructor was used to build the current object and inspect it for properties to suggest.

Article Start Previous Page 2 of 3 Next

Related Jobs

Giant Army
Giant Army — Remote, Washington, United States

Graphics Developer for Universe Sandbox
Hi-Rez Studios
Hi-Rez Studios — Alpharetta, Georgia, United States

Senior Technical Artist
Hi-Rez Studios
Hi-Rez Studios — Alpharetta, Georgia, United States

Unannounced Project - Gameplay Programmer
Build A Rocket Boy Games
Build A Rocket Boy Games — Edinburgh, Scotland, United Kingdom

Senior Animation Programmer

Loading Comments

loader image