Daniel Salvagni — Yet another software engineer
Things to be aware when you are starting in JavaScript
JavaScript is the world’s most misunderstood programming language, said Douglas Crockford. I tried to compile some topics which I think is too confusing to work with if you are just starting in JavaScript. It is almost about the scope.
Table of contents
- Scope
- What is Scope?
- Global Scope
- Local Scope
- Function Scope
- Lexical Scope
- The
this
keyword - Closure
- Hoisting
1. Scope
Different from other languages like C
, C++
or C#
, JavaScript doesn’t has block-level scope, but it has function-level scope. Which means that only function can create a new scope. They aren’t created by for
or while
loops or expression statements like if
ir switch
.
1.1. What is Scope?
Be aware that the scope refers to the context of your code so it could be globally
or locally
defined. Understanding it is key to be a better JavaScript developer by knowing where variables and function are accessible
and be able to change the scope of your code’s context when it is neccessary.
1.2. Global Scope
By default, when write a line of JavaScript you’re in what is called Global Scope
or Global Object
. So, if we are declaring a variable in the default scope, we are doing it on global scope.
Control the global scope is easy and in doing so, you’ll run into no issues with global scope. You’ll hear people saying “Global Scope is bad”, but it isn’t. You need it to creade Modules and APIs that are accessible across scopes and take it as your advantage.
Think about it as a global object where each global variable is present as a property of this object. In browsers, the global scope object is stored in the window
variable.
1.3. Local Scope
Everything defined past the global scope refers to local scope. You’ll have one global scope and for each function defined it has its own local scope. Like I said before, only functions can create new scopes. So, if I have a function with variables inside it, those variables are in the local scope (the function scope). Look at the example below.
We can’t access the fullName
variable because it is locally scoped and it isn’t exposed to the parent scope.
1.4. Function Scope
Just remember: Functions creates scopes.
1.5. Lexical Scope
Also called as Closure or Static Scope, Lexical Scope is the possibility of an inner scope access a variable or function in parent scope.
Lexical scope is easy to understand and work with. Just think that any variable, object and functions defined in it’s parent scope are available in the scope chain. The important thing to remember is that Lexical scope doesn’t work backwards.
##2. The this
keyword
this
keyword could be hard to use if you don’t exacly know how it works.
The this
keyword always refers to owner of the function we’re executing, or rather, to the object that a function is a method of.
Here is a few very important points to remember about the this
keyword:
- The
this
keyword value isn’t related to the function itself but how the function is called. So it can be dynamic. - Yoo can change the
this
context through .call(), .apply() and .bind()
Default context
We can change the this
vaue in a few different ways and it’s usually the caller of a function that can change his context.
Window Object, Global Scope
From a regular function declaration we can expect that the this
value would be window Object
, which refers to the global scope. The ownership of this
will be window
.
Object literals
In the case of Object literals, the ownership will be the it’s own Object.
So, why isn’t window
the ownership in this case? Because the window Object
didn’t call the function but someObject
did. It is the same for constructors
.
Prototypes and Constructors
In both cases above, the this
ownership is the Constructor object, which is musician
;
Events
Same rules are applied when we bind events. The this
refers to his owner.
To see how this
is dynamic you can just invoke the function and the return will be different from the event call.
Changing this
context
There are many reasons why we need to change the context of a function and we have a few methods that use can use to do it: .call()
,.apply()
and .bind()
.
You will use the methods above when you want this
to refer to something different thant the scope it’s in.
With .call()
and .apply()
we can pass a new scope and arguments. They immediately invoke the function.
Different from .call()
and .apply()
the .bind()
method doesn’t invoke the function when it is called. It is used to setup
the context for a function.
It can also be used in event handlers to add some extra information:
3. Closures
Private and public members in JavaScript is possible using closures. Closures treat functions as values, and as functions have his own scope, local variables are “re-created” every time a function is called. It emulates public and private scopes.
JavaScript have some design patterns, such as the Module
pattern which can create a public
and private
scope. As we know that functions create scope, we can create a private scope by wrapping a function inside other function:
We can add some functions for use:
Remember that the function is defined inside a private scope, so it isn’t possible to access it from the global scope:
So, that’s it! If we need the function to be public, we can now use the Module Pattern
which allow us to scope our functions using private and public scopes and an Object
. Basically, to turn a function public, we need to return a function or an Object
.
Module Pattern
So, follow this idea, everything that isn’t be returned is private.
You myght notice that JavaScript have a naming convetion to begin private
methods with an underscore, which visually helps you differentiate between public and private methods. This allow us to return an anonymous Object
simply assigning the function references.
4. Hoisting
Functions and variable declarations are always moved invisibly to the top of theirs containing scope by JavaScript interpreter. This JavaScript behaviour is called “hoisting”.
With variables, only the declaration name is hoisted. With function declaration
, the entire function body will be hoisted. It doesn’t is applied for function expressions
assigned to local variable. Follow the examples below:
This will be interpreted like this:
As this is applied to the scope, lets take a look in this function scope.
Will be interpreted like this:
Notice that only the name is hoisted, not the variables value. It isn’t he case with function declarations
, where the entire function body will be hoisted as well.
It is a good practice always declare your variables with just one var
statement per scope and that it be at the top. Forcing yourself to do this, will be hard to get into some hoisting-related confusion.
I hope it’s useful.