JavaScript Jems - Why JavaScript Is A Jem
Written by Mike James   
Monday, 24 January 2022
Article Index
JavaScript Jems - Why JavaScript Is A Jem
Prototype-Based

Prototype-Based?

In principle, JavaScript is also a prototype-based language where new objects can be created from existing objects, but in practice this is probably one of its weakest areas. In a prototype language, prototypes play the role of inheritance - one object serves as the basis for another object, providing it with a default set of properties and methods.

JavaScript originally implemented prototypical inheritance in a complicated way that makes use of a "helper" object, a function which acts as an object factory. The object factory creates instances of an object which provides a sort of basis for a type system - anything a given object factory creates is regarded as an instance of the same type. The only problem with this is that the instance can have properties and methods added or deleted at runtime which means that being of a particular type doesn't provide much information about the object unless you add some self-imposed rules.

In truth prototypes aren't really about inheritance, they are more about implementation efficiency. A prototype provides a packet of methods, i.e. code, that can be shared without duplication between any number of objects.

Modern JavaScript has provided additional and better prototype management options, but these haven’t really entered the mainstream consciousness of the JavaScript community and old ways die hard. In modern JavaScript prototypes are a jem, which you’ll find referred to repeatedly in this book.

Inheritance?

The object factory, or constructor, provides the mechanism of prototype inheritance. Any object created by an object factory uses the object factory's prototype property in an attempt to find any method or properties it doesn't implement directly. By setting the object factory's prototype property to another object you can implement inheritance and by prototype chaining you can also implement an inheritance hierarchy. This might sound like standard object-oriented inheritance, but it has its dynamic aspects. You can add properties and methods to the prototype object at runtime and so what is inherited can change at runtime.

This is inheritance, but not as we know it.

The problem is that the whole idea of the object factory and its role in inheritance and type isn't well thought out and it isn't complete. What is more, it isn't well enough understood by the average, or even expert, JavaScript programmer to really be used in a way that doesn't just mimic a broken implementation of classical inheritance.

JavaScript's dynamic objects are almost certainly best used without the help of type and with minimal use of classical inheritance. The problems that it seems to have are mostly due to the way we attempt to use it.

The key idea, as already mentioned, is that prototypes are not really about inheritance, they are about efficient sharing of code between multiple objects.

Asynchronous Programming

Asynchronous programming is the big programming problem that we fail to tackle head on. Languages like Python that come without a standard user interface don’t naturally encounter the async problem and mostly it doesn’t make an appearance in the language until much later – it isn’t a core issue.

However, for JavaScript async code is a core issue because, right from the first program you write, you have to confront the use of the UI, i.e. the web page. By default your program runs in the same thread as the UI and this means if you block the thread then the UI, the web page, freezes. This is obviously not a good idea and so JavaScript is inherently event-driven. However, in the early days it didn’t have any special facilities for asynchronous programming and so the standard paradigm of the “callback” was used for asynchronous behavior that did not fit into the event model. Callbacks are a terrible idea in that they are difficult to manage, make error handling harder and distort the natural flow of control.

As a first step to making async code natural in JavaScript, the Promise object was introduced. This was a jem in its own right, but soon afterwards it was combined with the new async and await statements that transform asynchronous code into something that looks like synchronous code. The way that Promises and async/await fit together to produce something amazing is a jem worth study, see Jem14. When added to the ability to start additional threads using Web Workers then the problem of asynchronous code in JavaScript is almost a solved issue.

Modern JavaScript is async-equipped.

A Functional Language

The second big aspect of JavaScript that tends to be overlooked is that it is a functional language. In it functions are not just "first class" they are "first class objects" - they have methods and properties and can be passed into and returned by functions like any other data type. Essentially a function is an object that carries a special method that is executed by the invoke operator i.e. a pair of round brackets ().

You can argue that having functions as first class objects is actually against the functional programming idea because it allows yet another way for functions to record state information. However, it might also be said that having functions as objects provides additional opportunities above and beyond the restrictions of functional programming.

As well as first class functions JavaScript also supports closures, recursion and dynamic modification of code. Closures are something that most beginners don't understand and when they do understand they have no idea how to make use of them. Closures make asynchronous programming, i.e. event handling, much easier and cleaner. If you look at most event handling in JavaScript you will find that this isn't the way that it is done, however, - another example of how JavaScript is misunderstood by many of its users.

If closures are generally misunderstood or misused, then what can you say about recursion and code modification? Recursion is a problem for the average programmer in almost any language and JavaScript is no exception. You may be able to use it, but do you know how to use it?

JavaScript does, however, omit a lot of very basic functional programming features. In particular there are no immutable data structures, with the exception of the String, and it lacks tail recursion optimization.

What all this means is that while JavaScript may not be a good language for strict functional programming, it allows the adoption of a functionally-oriented approach that has many of the benefits of a functional approach without the difficulties.

kindlecover

Extensibility

The fact that you can add many of the standard features of functional programming using a library brings us to the final topic - extensibility. JavaScript is an example of a minimal, but highly extensible, language. You can create JavaScript functions that mimic the features of just about any language. This has resulted in lots of big and useful JavaScript libraries - jQuery, script.aculo.us, Prototype, React, Lodash and so on. The only problem with this is that there isn't one big official JavaScript framework that you can devote your attention to. Choice isn't always a good thing in programming languages.

Shortcomings?

At the end of the story I have to be fair and point out that JavaScript has a lot wrong with it. It could do with some additional features such as access modifiers, threading, and the better facilities to manipulate the prototype pointer and control evaluation context. However, all of these are small additions that could be made without fundamentally changing the language. What is a more serious lack is the sort of IDE support we take for granted for "serious" languages such as Java or C#. In many ways it is not JavaScript that needs changing but its implementation and toolchain.

There are also well-intentioned, but poorly chosen, ways of working. JavaScript tries its best to be type-neutral and to not bother the programmer with irrelevant representational changes. What does it matter if the basic data type is 1.0, 1 or “1”, they are all representations of the number one. However, JavaScript’s data coercion can seem illogical unless you understand the logic. In many ways it is a flawed jem which is the source of a lot of criticism of the language.

Just remember the next time you approach a JavaScript task - you are working with a dynamic, untyped, functional,  prototypical, object-oriented language and not "just a script".

Many of these ideas are picked up again and explained in detail in the following jems. It is important to not approach what follows with an idea that there is a right way to do the job and there is no scope for doing things differently. Many of the perceived problems with JavaScript are the result of noticing that it doesn’t do what Java, C++ or some other language does and in attempting to make it conform the ugliness just proliferates.

JavaScript isn’t like other mainstream languages, but this doesn’t make it wrong.

Now available as a book from your local Amazon.

JavaScript Jems:
The Amazing Parts

kindlecover

Contents

<ASIN:1871962579>

<ASIN:1871962560>

<ASIN:1871962501>

<ASIN:1871962528>

espbook

 

Comments




or email your comment to: comments@i-programmer.info

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.

 



Last Updated ( Monday, 24 January 2022 )