Potential misconceptions when learning Javascript as a Java or C# developer

Modern day software programming is an increasingly wide and complex field. An ‘ideal’ full-stack developer would probably be one that started developing applications at a young age, developing knowledge and understanding of a broad number of technologies. She or he would have received formal education in different programming paradigms in several different languages, as well as in (relational) databases, communication protocols, hardware, security strategies, front-end technologies, etcetera.

Having first learned what a string and an integer are some 3 years ago, I am not such a developer. I know many other colleagues and friends for which software development was a taste that they acquired at a later age. There could be several reasons why software development is a popular choice of career switch. It is a relatively young profession, so perhaps some people are only now ‘discovering’ it. Perhaps people have a (probably unwarranted) fear that the profession is boring, or too difficult.

Whatever the reason, people who want to learn building software applications professionally today will initially have to find a way through an overwhelming number of technologies and concepts. You have little choice in this case, but to simply start somewhere. For me that somewhere was (primarily) ASP.Net and C#. After following some (open) university courses about object-oriented programming (in Java) and subsequently landing a job as junior C# developer, I quickly felt somewhat competent in basic programming in C#. Classes, interfaces, inheritance, and those sorts of things. The C# and Java languages of course have their differences (that I won’t discuss here), but I would argue that they are conceptually similar.

Some knowledge of object-oriented and class based programming was a narrow window of entrance into a wide field of technologies. To contribute to the development process of full web applications, I had to at least develop some basic ability to (amongst others) work with things like HTML and HTTP/Ajax. And: Javascript.

Superficially, Javascript seems somewhat like C# (except for some obvious differences like strong typing and classes).  But Javascript has been a somewhat rough experience for me so far. After taking some time recently to get more familiar with the core concepts of plain Javascript as a language however, things start making more sense.

Javascript is actually, in many ways, very much different from C# or Java and I believe that a basic, structured, overview of the most fundamental differences might help junior Javascript developers, like me, with the following things:

-Some understanding of the inner workings of popular libraries we tend to use like Typescript, various module loaders, Angular, etc.

-More awareness of good and bad coding practices when writing Javascript.

-Detecting and understanding ‘bugs’ in Javascript code that we could not understand if we treat it like it was, say, C#.

-Powerful features that are unique to Javascript and that we can use to our advantage.

In this article, I will assume that the reader is familiar with C# and- or Java and zoom in on those aspects of Javascript that may be most confusing to developers that are familiar with those languages.

 

Every data container in Javascript is either an ‘object’ or a ‘primitive’ (and that’s all)

Primitives in Javascript are not objects and they are always 1 of the following 5 things: number, string, bool, null and undefined.  String, bool and null are somewhat similar to how they work in C#/Java. One notable thing though, is that Javascript has no stack and heap separation in terms of memory allocation. In other words, there is no such thing as a struct in Javascript. Thus, the implication of data being captured in either an object or a primitive is minimal in memory terms.

Also, the ‘under-water’ way in which Javascript enables methods to be called on a string literal (e.g. string.length), is completely different from C# and Java. I’ll come back to that later when talking about object prototypes.

Javascript numbers are always 64-bit floating point variables. There is only the one type of number (so no double, decimal, etc.).

All objects declared in the Javascript language always have this exact structure:

{

key1: value1,

key2: value2,

key3: value3,

// ..etc,

key100: value100,

// …etc

}

The values in this case can be primitives, or other objects. Note that functions in Javascript are objects themselves, just like arrays.

Compared to C#/Java objects, Javascript objects have no type (by default) and do not need to instantiate a class.

The undefined primitive is the value that variables receive when they are declared but have not yet received a value. Somewhat confusingly, you can also assign the value undefined manually, like so:

var x = undefined;

var y = {key1: undefined};

Doing this is considered bad practice but it is good to understand the difference between an undefined variable, a variable with the value null and a ‘unknown’ variable. In Java and C#, declared but unassigned variables have a default value (null for reference types, 0 for Integer, false for bool etc.). In Javascript this default value is undefined for everything. Null is typically used in Javascript when you want to explicitly not assign any value to something (a method could typically return null for example, as opposed to undefined). Finally, when a variable that has not been declared at all is used during execution of the code, the compiler will throw an unknown variable exception.

 

Program flow in Javascript is single threaded, starts with a root ‘this’ object and flows from top to bottom in the second phase of its execution.

Ok, that header is certainly a mouthful. Please bear with me and I’ll explain. Program flow in Javascript is fundamentally different from C# and Java and some insight into how it works is very helpful in understanding when things in your code happen and why.

Code execution (compilation) of a Javascript app proceeds in two phases. In the first phase, the Javascript compiler prepares the ‘execution context(s)’. In the second phase those execution contexts are, well, executed. I.e. it is translated by the compiler into code that the computer can understand.

The first of the execution contexts that is prepared by the compiler is called the global execution context. This is the outer scope of your Javascript app. It always comes with a global object that is called ‘this’. In the case of Javascript executed in a web-page, ‘this’ is (in the global scope) normally the window object. Furthermore, each ‘function’ in your app gets its own execution context. These execution contexts are prepared for execution in the order in which they are nested under the outer scope, and from top to bottom. Because this may be easier to follow with some visual example, I refer to the following post that I found on the web and that explains this topic very well:

https://cedric-dumont.com/2015/10/31/compilation-and-execution-phases-of-simple-javascript-code

The ‘this’ variable for each execution context, by default, points to whatever object is currently in scope. That essentially means that ‘this’ initially points to the object on which the function which encapsulates the current execution context is called. The nature of ‘this’ in Javascript is extremely confusing, especially for developers used to C# or Java.  However, the following document does a fair job of explaining it:

https://developer.mozilla.org/nl/docs/Web/JavaScript/Reference/Operators/this

In the second phase, once all execution contexts are prepared, the code on them is then executed for each context in sequential order and on a single thread. Javascript code, unlike C# and Java applications, has no classes or methods that can start new threads.

Variables that have been declared but that have not received a value at the time of code execution will have the default value (undefined), as explained earlier. Note that this can be for any reason: You may have forgotten to assign the variable, or the variable may get assigned only after a promise has resolved and that promise has not returned yet. The same holds true for variables that are assigned to a function. The following code for example will throw an exception because x is undefined, just as if x were any other object (Remember, there is only one type of object in Javascript).

x();

var x = function(){ console.log(‘Called x!’);};

By contrast, the following code will work, and show ‘Called x!’ on the console:

x();

function x() { console.log(‘Called x!’);};

This last type of function is evaluated as soon as the execution context in which it resides is generated and will be placed on that scope as an object-function called x.

 

The new keyword in Javascript is used when creating new instances of objects using constructor functions. Not when simply creating a new object by defining it and assigning it to a variable.

The ‘new’ keyword, much like the ‘this’ keyword is a strange beast in Javascript. Perhaps this is even more true because it was introduced to Javascript at a later point in time, with the intention to make the instantiation of new objects look and feel like regular Java. What makes it confusing is that, in practice, it does something completely different and is not comparable with the new keyword in C# or Java.

Let’s start by explaining what ‘new’ does in Javascript. Consider the following ‘constructor’ function and assume that you placed this function on the global execution context:

function Person(first, last, age, eye) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eye;
}

The reason this type of function is called a constructor function is that it can be used to create new instances of objects that look like this:

{

firstname: ‘firstname’

lastname: ‘lastname’,

age: number,

eyecolor: ‘value’,

__Proto__: {

contructor: function Person(first, last, age, eye)

}

To accomplish this, we need to simply write:

var x = new Person(‘first’, ‘last’, number, ‘eye’);

What we certainly do not want to do is write the following:

var x = Person(‘first’, ‘last’, number, ‘eye’).

If you fail to see why this is, you should probably read the former paragraph about program flow and the ‘this’ keyword once more. Because it is an easy mistake for a programmer to make, declaring the Person function with a capital P is an unusual but important convention here. Normally functions and variables in Javascript always start with a lowercase letter. (Incidentally, another difference with Java and C#).

I will talk about the _Proto_ (‘prototype’) object a bit more in the last paragraph. For now, it is important to see that objects you create with a ‘new’ keyword retain a reference to (a copy of) the function that created them via this prototype object. All ‘children’ that you create off the constructor function have a reference to the same prototype object. This is the basis for prototypical inheritance in Javascript. A completely different mechanism to inheritance as we know it in C# and Java.

 

Using object prototypes in Javascript to your advantage

Each object in Javascript has a hidden reference to a prototype object, with Object.prototype always being at the end of that reference chain.

All properties and methods of an object’s prototype, are accessible by its ‘children’ as well. Let’s say we create a new object in the normal way, like so:

var normalObject = { quality: ‘normal’, type: ’object’   };

This normalObject has, by default, a reference to Object.prototype and that is why you can call a method like ‘toString()’ on it. Primitives do not have a prototype object, but strangely you can call methods on them. This is made possible due to Javascript very briefly creating the necessary object representation of that primitive, use that objects’ String.prototype methods, then garbage-collect the object immediately after. For example: ‘test’.charAt(0) will be briefly converted to new String(‘test’).charAt(0) upon executing the code.

Because all child objects made by a constructor function share the same prototype object, you can do funny things, that are somewhat unexpected when you are used to Java/C#. You can, for example, extend commonly used object prototypes like Array.protoype, Window.prototype ans String.prototype (each of which has its own reference to Object.prototype), with you own methods*. This feels almost like extension methods in C#.

You can also create an object with the new operator, then change its prototype to an entirely different object, to create various interesting effects. It is fun to play around with and I would encourage the reader to experiment, to get a good feeling of object behavior in Javascript.

*If you are using typescript, remember to also extend the type-definition interface, to get this to work.

 

Closing words

Javascript is an interesting language that has its weaknesses but certainly has a lot of strengths as well. Because Javascript is the backbone of nearly all client-side code in web-applications, often with complex frameworks like typescript and angular built on top of it, I believe there is a lot of value in understanding how it works on a fundamental level for nearly every developer. While it looks somewhat like Java and C# on a superficial level, I hope I have given a good impression of the points at which it is very different. I also hope that this write-up was of some use to other people learning Javascript as a secondary language.

 

 

 

Tweet about this on TwitterShare on LinkedIn

Reacties

Het e-mailadres wordt niet gepubliceerd.

*