JavaScript traits: the clean way to modify global prototypes

Implementing decent traits in JavaScript through duck typing and prototypal inheritance used to have problems, but since a recent version of the language (ECMAScript 6) added a new primitive data type (symbol), the situation has improved.Very few are using this exciting feature of the language though, and that’s what motivated this article.What are traits?Traits are a way to add semantics to existing types without risking unintentional interference with existing code.Traits are an alternative to inheritance as a method for implementing polymorphism, and all the modern languages have them: think of go, haskell and rust just to name a few.JavaScript is a prototypal, duck typed language, and this has always allowed programmers to do something very similar just by adding a new property to an existing prototype..But this simple addition has major problem and should be avoided..In fact you should never modify the prototype of types you don’t own, and that’s why most libraries go out of their way to offer new functionalities to existing types without actually modifying those types.Recent versions of JavaScript (i.e. ECMAScript 6) added a new primitive data type, symbol, which can be used to implement traits effectively..A symbol is basically a unique identifier that can be used as a property and that will never collide with anything else..In ECMAScript 6 they needed a way to expand standard types without breaking compatibility with existing code..That is why they introduced symbol, and they're indeed using it to implement traits..However, instead of advertising this new feature and making traits a first class citizen, they have let symbols remain in the shadows..The standard calls this feature protocol, instead of trait, and one of several examples is the iteration protocol.Besides the lack of guidelines and good examples, another issue makes it tough to use symbols as traits: a lack of good syntax to do so.But enough talking!.Let’s look at an example.Why do we need traits?.An exampleImagine that you need a serializer to convert pieces of data into a string that can be stored somewhere.JSON.stringify() is not good enough, as it doesn't support "complex" objects (try to stringify a circular object, a RegExp, a Map etc, and you'll see).Well, let’s write our own serialization function then..We want to support primitive data types (boolean, number, string etc), built-in types (Array, Map, RegExp etc), as well as the classes we or somebody else define..Something might be impossible to serialize, like Functions or Promises, and that's OK: we'll just throw an error if we're given to serialize one of these.What we are trying to do, is to add a new serializing logic to most types, regardless of whether they’re defined by us, by other people, or built-in in the language.. More details

Leave a Reply