Some Intermediate Concepts of Javascript
Undefined:
Undefined value primitive value is used when a variable has not been assigned a value.
The standard clearly defines that you will receive undefined
when accessing uninitialized variables, non-existing object properties, non-existing array elements, and alike.
let movie = { name: 'Nobody' };
movie.year; // => undefined
Undefined type is a type whose sole value is the undefined
value.
A declared variable but not yet assigned with a value (uninitialized) is by default undefined
.
Favor const
, otherwise use let
, but say goodbye to var
const
and let
are block scoped (contrary to older function scoped var
) and exist in a temporal dead zone until the declaration line.
When accessing a non-existing object property, JavaScript returns undefined
.
let favoriteMovie = {
title: 'Blade Runner'
};
favoriteMovie.actors; // => undefined
JavaScript offers a bunch of ways to determine if the object has a specific property:
obj.prop !== undefined
: compare againstundefined
directlytypeof obj.prop !== 'undefined'
: verify the property value typeobj.hasOwnProperty('prop')
: verify whether the object has an own property'prop' in obj
: verify whether the object has an own or inherited property
Private variable:
In object-oriented programming languages, there is a way to limit the visibility of a variable from outside its scope. In other words, some programming languages allow variables to only be accessible by the object that “owns” it.
class Example {
// hiddenVariable CAN only be accessed here
private String hiddenVariable;
public Example(String websiteName) {
hiddenVariable = websiteName;
}
}
Encapsulations:
The easiest way to achieve pseudo-encapsulation would be to prefix your private member with a special symbol that indicates the private scope to the client. It is a common convention to use the _
symbol as a prefix.
Closures
In JavaScript, when a function finishes executing, any variables declared within its body is “garbage collected”. In other words, it is deleted from memory. This is why local variables are possible in JavaScript. This is why variables inside functions cannot be accessed outside.
// dev is NOT accessible here
function someFunc() {
// dev is accessible here
const dev = 'to';
}
// dev is NOT accessible here
Factory Functions
A factory function is any function that returns an object. Yup, that’s pretty much it. This is not to be confused with classes and constructor functions. Classes and constructor functions require the new
keyword to instantiate objects while factory functions return the instantiated object itself.
function factory(name) {
return { name };
}const obj = factory('Some Dood');
console.log(obj.name); // 'Some Dood'
Bind(),Call(),Apply():
In object-oriented programming languages, the this
keyword always refers to the current instance of the class. Whereas in JavaScript, the value of this
depends on how a function is called.
We use call, bind and apply methods to set the this
keyword independent of how the function is called. This is especially useful for the callbacks
Bind( )
The bind method creates a new function and sets the this
keyword to the specified object.
Syntax:
function.bind(thisArg, optionalArguments)
For example:
Let’s suppose we have two person objects.
const john = {
name: 'John',
age: 24,
};const jane = {
name: 'Jane',
age: 22,
};
Let’s add a greeting function:
function greeting() {
console.log(`Hi, I am ${this.name} and I am ${this.age} years old`);
}
We can use the bind
method on the greeting
function to bind the this
keyword to john
and jane
objects. For example:
const greetingJohn = greeting.bind(john);// Hi, I am John and I am 24 years old
greetingJohn();const greetingJane = greeting.bind(jane);// Hi, I am Jane and I am 22 years old
greetingJane();
Here greeting.bind(john)
creates a new function with this
set to john
object, which we then assign to greetingJohn
variable. Similarly for greetingJane
.
We can also use bind in case of callbacks and event handlers. For example:
const counter = {
count: 0,
incrementCounter: function() {
console.log(this);
this.count++;
}
}document.querySelector('.btn').addEventListener('click', counter.incrementCounter.bind(counter));
In the above example, the this
keyword inside the incrementCounter
method will now correctly refer to the counter
object instead of the event object.
Bind() accept arguments:
We can also pass extra arguments to the bind method. The general syntax for this is function.bind(this, arg1, arg2, ...)
. For example:
function greeting(lang) {
console.log(`${lang}: I am ${this.name}`);
}const john = {
name: 'John'
};const jane = {
name: 'Jane'
};const greetingJohn = greeting.bind(john, 'en');
greetingJohn();const greetingJane = greeting.bind(jane, 'es');
greetingJane();
In the above example, the bind
method creates a new function with certain parameters predefined (lang
in this case) and this
keyword set to the john
and jane
objects.
Call ( )
The call method sets the this
inside the function and immediately executes that function.
The difference between call()
and bind()
is that the call()
sets the this
keyword and executes the function immediately and it does not create a new copy of the function, while the bind()
creates a copy of that function and sets the this
keyword.
Syntax:
function.call(thisArg, arg1, agr2, ...)
For example:
function greeting() {
console.log(`Hi, I am ${this.name} and I am ${this.age} years old`);
}const john = {
name: 'John',
age: 24,
};const jane = {
name: 'Jane',
age: 22,
};// Hi, I am John and I am 24 years old
greeting.call(john);// Hi, I am Jane and I am 22 years old
greeting.call(jane);
Above example is similar to the bind()
example except that call()
does not create a new function. We are directly setting the this
keyword using call()
.
Call () accept arguments:
Call()
also accepts a comma-separated list of arguments. The general syntax for this is function.call(this, arg1, arg2, ...)
For example:
function greet(greeting) {
console.log(`${greeting}, I am ${this.name} and I am ${this.age} years old`);
}const john = {
name: 'John',
age: 24,
};const jane = {
name: 'Jane',
age: 22,
};// Hi, I am John and I am 24 years old
greet.call(john, 'Hi');// Hi, I am Jane and I am 22 years old
greet.call(jane, 'Hello');
Apply ( )
The apply()
method is similar to call()
. The difference is that the apply()
method accepts an array of arguments instead of comma separated values.
Syntax:
function.apply(thisArg, [argumentsArr])
For example:
function greet(greeting, lang) {
console.log(lang);
console.log(`${greeting}, I am ${this.name} and I am ${this.age} years old`);
}const john = {
name: 'John',
age: 24,
};const jane = {
name: 'Jane',
age: 22,
};// Hi, I am John and I am 24 years old
greet.apply(john, ['Hi', 'en']);// Hi, I am Jane and I am 22 years old
greet.apply(jane, ['Hola', 'es']);
Callback function
A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action.
Here is a quick example:
function greeting(name) {
alert('Hello ' + name);
}function processUserInput(callback) {
var name = prompt('Please enter your name.');
callback(name);
}processUserInput(greeting);
Event bubbling and delegation:
Events:
In JavaScript, when users interact with the page, their actions are captured in form of events
- When users interact with a web page, their actions are registered in form of events
- A listener receives an object parameter, which contains data about the triggered event
Event bubbling:
Event bubbling is the propagation of an event from its origin towards the root element.
if an event occurs on a given element, it will be triggered on its parent as well and on its parent’s parent and all the way up, until the html element. If any of these elements has one or more registered listeners, they will be called. Therefore, the bubbling effect is only noticeable when at least one ancestor of the event’s origin has a listener for the same type of event. Otherwise, the propagation will happen silently, since there’s no listener to be called.
- Event bubbling is the propagation of an event from the element where it happened towards the root element
document.getElementById('header').addEventListener('click', () => {
console.log('Header click');
});
Event delegation:
Event delegation leverages the bubbling effect to extract the handling logic of an event to a common ancestor of the elements where this event is triggered.
- Event delegation makes it possible to handle events triggered by many elements in a single place.