1. Dynamic Typing
Because of that, there’s not much difference in defining variables and assigning them data of various data types:
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
3. null and undefined
4. Truly and Falsy values
- “falsy” values: undefined, null, 0, ”, NaN
- “truly” values: all NOT falsy values
Knowing that you might want to check if the value has been defined in the following way:
So the proper way of checking whether the number has been defined is as follows:
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.
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:
So here we call the function before declaring it. Why does this work?
It however applies only to declarations, not to assignments:
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:
It means that other blocks like the ones associated with if statement don’t introduce a new scope:
If a variable is defined outside of any function, it’s assigned to a global scope.
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:
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:
However, if we just define an inner function in our method and try to print this keyword inside it, weird stuff happens:
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).
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:
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.
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.
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.
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:
As a result of executing such script in a web browser, we’ll see the following console output:
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”:
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.
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 😉 ):