10 Most Shocking JavaScript Features for C# Developers

Whether you’re a C# (or similar language like Java) developer eager to learn JavaScript or you’ve already been working with JS for some time, I hope you find this article interesting. I collected for you 10 JavaScript features which are/were the most shocking for C# developers who learnt JavaScript.

These features of JavaScript language are the most striking differences compared to C# ecosystem. If you’re about to learn JavaScript, sooner or later you’ll also have to deal with them.

Before we begin, one disclaimer: the goal of this post isn’t stating which language is better or worse. JavaScript and C# are different programming languages and their use cases are also completely different. One is better for some usages, while the other is better for others. The list is my and other readers’ subjective one and you don’t need to agree with all points. I’m myself a C# developer on my JavaScript learning journey, so I’d like to help you grasping these confusing concepts 😉

1. Dynamic Typing

Obviously, the first difference JavaScript newbie notices is that the language is dynamically-typed. It means that the types (of variables, functions, actually of almost everything) are checked at runtime, not at compile time like in C# or Java.

Because of that, there’s not much difference in defining variables and assigning them data of various data types:


var someNumber = 1;
var someBoolean = true;
var someString = 'Hello JS!';

JavaScript’s variables are not associated with any particular data type. That’s why it’s completely legit to write something like that:


var a = 1; // typeof a => number
a = true; // typeof a => boolean
a = 'Hello JS!'; // typeof a => string

view raw

JS_dynamic.js

hosted with ❤ by GitHub

Because JavaScript is dynamically-typed, issues with types are detected at runtime (e.g. error is thrown as soon as you try to use a variable in a context which expects another data type), not during compilation time as it would be in C# or Java.

If you have some experience with statically-typed languages, you may now feel how much confusion and troubles dynamic typing can bring. At least at the beginning.

2. Implicit types coercion

JavaScript has one more interesting feature – types coercion. Even though this term’s name sounds a bit weird 🙂, it’s quite simple: types coercion happens when a value of one type is converted to another one.
 
It may be explicit, but harder to grasp is the implicit types coercion. It means that developer doesn’t necessarily ask for converting value of some type to another, but it still happens “silently”. To visualize it, consider the following code:


var name, isGreatDeveloper;
name = 'Dawid';
isGreatDeveloper = true;
console.log('Is ' + name + ' a great dev?: ' + isGreatDeveloper);
// displays 'Is Dawid a great dev?: true'

Even though console.log() expects data of text type, isGreatDeveloper which holds a boolean value at the moment is implicitly converted to text.

The above example was just to show you what types coercion is all about, but it gets more confusing in reality. First misleading concept is that JS has actually two equality operators: == and ===.

Let’s see some code example to know the difference between them:


var age = 26;
if(age == '26'){
// this is executed
}
if(age === '26'){
// this is NOT executed
}

The first == operator performs an implicit types coercion before performing the actual comparison. That’s why the text ’26’ is “silently” converted to a number 26 and the if statement is true at this point.

Because of that, we should normally always use === operator to avoid such unclear situations.

Existence of such (and many more) nice concepts of JavaScript leads to finding such interesting Tweets:

If you want to dig into types coercion, you can read this article.

3. null and undefined

In JavaScript there are two values which represent kind of unassigned variables: undefined and null. What’s the difference between them? The snippet below clarifies:


var x;
console.log(x); // prints 'undefined'
x = null;
console.log(x); // prints 'null'

As soon as you declare a variable, but don’t assign any value to it, it contains undefined. It may contain null if it was assigned to it, either explicitly as in the example or as a result of some operation.

I see it as the names suggest: undefined is something that has really not been defined (assigned) yet, while null is more like a special kind of value which has some useful meaning.

4. Truly and Falsy values

As we already know null and undefined,  it’s important to note that there are some “falsy” and “truly” values in JavaScript:
  • “falsy” values: undefined, null, 0, , NaN
  • “truly” values: all NOT falsy values
It means that “falsy” values are implicitly converted to false boolean value e.g. in comparison context:


var x; // x is 'undefined'
if(x){
// this is NOT executed
}

view raw

JS_falsy.js

hosted with ❤ by GitHub

Knowing that you might want to check if the value has been defined in the following way:


if(x){
console.log('x is defined!');
}

However, assuming x is a number, this will not work if x has a value of 0, which is also one of the “falsy” values.
So the proper way of checking whether the number has been defined is as follows:


if(x || x === 0){
console.log('x is defined!');
}

Of course, for another data types (like text) you need to handle other “falsy” values as well. It depends what you consider a meaningful value.

5. Hoisting

In JavaScript you can legally write such a code:


name = 'Dawid';
console.log(name);
var name;

view raw

JS_hoisting.js

hosted with ❤ by GitHub

As you can notice, name variable is used before it’s declared 2 lines below. This is maybe not that weird, as in JS we can even declare variables without the var keyword, but we can do the same with functions:


printHello(); // prints 'Hello!'
function printHello(){
console.log('Hello!');
}

So here we call the function before declaring it. Why does this work?

This works thanks to hoisting. It’s a compile-time mechanism which “moves” all variables and functions declarations to the top of our JavaScript code. In fact, during the execution of above-listed code, JavaScript engine processes variables and functions declarations before executing any other code.

It however applies only to declarations, not to assignments:


console.log(name); // prints 'undefined'
var name = 5;

In this case, only var name part of the declaration and assignment is “moved to the top” and executed first. The assignment part (=5) is not. That’s why when calling console.log(name) the name variable is undefined.

Because of hoisting, we should declare and preferably assign all variables used in the given scope at the top of it.

6. Lexical scoping and this keyword

To create a scope (space in which the variables defined in it are accessible) in JS, we need to create a new function. Variable defined in a function is not accessible outside this function:


function a() {
var x = 5;
}
console.log(x); // Uncaught ReferenceError:
// x is not defined

It means that other blocks like the ones associated with if statement don’t introduce a new scope:


if(true) {
var x = 5;
}
console.log(x); // prints '5'
// x is a global scope variable

view raw

IfBlock.cs

hosted with ❤ by GitHub

If a variable is defined outside of any function, it’s assigned to a global scope.

However, in JavaScript we also have something called lexical scoping. It basically makes functions declared within another functions having access to the parent function’s scope, as the following example presents:


function a() {
var x = 'Hello';
b();
function b() {
var y = ' world!';
console.log(x + y);
}
}
a(); // prints 'Hello world!'

Forming such “hierarchy” of functions is also referred to as scope chain. You should remember that it refers to the order in which functions are lexically written, not in which they are called:


function a() {
b();
function b() {
var x = 'Hello world!';
c();
}
}
function c() {
console.log(x); // Uncaught ReferenceError:
// x is not defined
}
a();

As you can see above, as soon as we call a(), which then calls b(), within which we define variable x and then call function c(), inside of function c() we don’t have access to x variable (x is not defined). Why does it happen even though function b() in which x variable is declared called function c()? Because function c() is not lexically written as the child function of b(). Parent scope for function c() is always the global scope.

7. this keyword

All these scoping rules examined above somehow lead to another confusing concept with this keyword. As soon as we define a method on some object and try to print the this keyword in this object’s method, the result seems reasonable:


var blogger = {
name: 'Dawid',
website: 'codejourney.net',
aboutMe: function(){
console.log(this);
}
}
blogger.aboutMe(); // prints: {name: "Dawid", website: "codejourney.net", aboutMe: ƒ}

view raw

this_1.js

hosted with ❤ by GitHub

However, if we just define an inner function in our method and try to print this keyword inside it, weird stuff happens:


var blogger = {
name: 'Dawid',
website: 'codejourney.net',
aboutMe: function(){
function innerFunc(){
console.log(this);
}
innerFunc();
}
}
blogger.aboutMe(); // (!!!) prints: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}

view raw

this_2.js

hosted with ❤ by GitHub

As you can see, the this keyword in the innerFunc() function doesn’t point to the blogger object anymore. Instead it points to a Window object, which represents the browser’s window (this used in the global scope points to it).

This happens because in a regular function the this keyword points to the global object (Window object in our case). innerFunc() is here considered as a regular function, not as an object’s method. This behavior may be confusing and is often a subject of dispute in JavaScript community.

8. sort() function

You’re a newbie JS developer and you’d like to sort an array of numbers. You found a sort() method on the array, so why not to use it? You write such code:


var numbers = [40, 20, 15, -5, 7];
console.log(numbers.sort());

view raw

sort_numbers.js

hosted with ❤ by GitHub

What do you expect to be logged in the console? Let’s see:

(5) [-5, 15, 20, 40, 7]

Nice! What happens here? 7 is greater than 40? Well, yes 🙂 It works as expected, because the sort() function sorts array’s elements as strings and alphabetically. Therefore, if our array contains numbers, the final order depends on the Unicode representations values of each number.

Fortunately, there are ways to use sort() function correctly for numbers, but this functionality is still confusing for new JavaScript developers.

9. Prototypes

Every object in JavaScript has a __proto__ property. We can access it directly on our object or by using Object.getPrototypeOf() method. In both cases, having created an empty object and printing its prototype to the console like that:


let x = {}
console.log(x.__proto__);

view raw

Prorotype.js

hosted with ❤ by GitHub

produces the same output:

On the top of objects hierarchy, there’s Object. Because of that, our x object is an instance of Object. That’s why the prototype of our x object is actually the Object.prototype, which contains some common methods we can use (like toString()).

If we try to access Object.prototype.__proto__, we’ll see that is contains null.

Prototypes in JavaScript are mainly used to provide some connection between two or more objects (like exposing some common methods).

All this “hierarchy” of prototypes is used to search for fields and methods of objects: the JS engine first searches in the object itself and if it cannot find particular property, it looks in this object’s prototype, and then in its prototype until it finds the first matching occurrence. As soon as it reaches null in the Object.prototype.__proto__ it means that the prototypes chain has ended and undefined is returned.

This kind of prototype inheritance is different than class inheritance, so it’s often confusing for developers willing to learn JavaScript. Actually, I could write a separate post on this, so if you’re interested you can read more for instance here.

10. IIFE

IIFE is an acronym for Immediately-Invoked Function Expression. So what is it and how can it be useful?

Going straight into the code, IIFE can be written as follows:


(function() {
console.log('Hey!');
})()

view raw

IIFE.js

hosted with ❤ by GitHub

As a result of executing such script in a web browser, we’ll see the following console output:

Hey!

How does it work? We neither declared a function’s name nor called it, right? Actually, we did 🙂

There are two unusual parts of IIFE implementation: outer parentheses in which we “wrapped” our function and “empty” parentheses together at its end.

Let’s start by “wrapping parentheses”:

Why do we declare them? Because if you don’t, JavaScript parser will give you an error:

script.js:1 Uncaught SyntaxError: Unexpected token (

In such case it thinks that we’re writing a function declaration and we forgot about providing the function’s name after the function keyword. Wrapping this into parentheses (…..) tells the parser that we’re declaring a function expression, not a declaration. After doing this, there are no errors anymore.

The second important part is the “empty” parentheses () just after the function expression:

As you know, () allows to call the function. That’s exactly what we do here here – our function is immediately executed.

Why would we need such construct as IIFE? Developers say that it doesn’t “pollute” the global scope. In effect, we are not leaving the function somewhere after being executed, so no one else can call it accidentally from another place. What’s more, IIFE is even considered a design pattern.

You should know that such construct exists even only to know what it does seeing it in someone else’s code. If you want to know more about its use cases, I recommend reading this article.

Summary

In this post we’ve gone through some of the most shocking features of JavaScript language for C# developers. Most of them are confusing for programmers coming from statically-typed and class-based languages and can bring a lot of issues in the beginning of their JavaScript journey.

Just remember that these are the JavaScript’s language features, not its issues or bugs. That’s just how it is, but it cannot be said that JavaScript is worse or better than other languages like Java or C#.

The list for sure is not exhaustive, so if you have anything to add or correct don’t hesitate to leave a comment! 🙂

For the end, I’ll just leave you with the following meme-but-true (thanks Youenn 😉 ):

Source

Stay tuned!

GET A FREE GUIDE 🎁

16 STEPS TO BECOME
.NET FULL STACK WEB DEVELOPER
IN 2023

After you sign up, I may be sending you some emails with additional free content from time to time.
No spam, only awesome stuff

 

.NET full stack web developer & digital nomad
0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments