Member preview

Ten Fundamental Javascript Concepts

Data Types

Data types are the different types of data that Javascript can operate with. They can be organized in two groups: Primitive types and reference types. Primitive types are simple, immutable values such as numbers and text sequences that can be stored as such.

There are six types of data types that are primitive:

  • Number
  • String
  • Boolean
  • Null
  • Undefined
  • Symbol

Reference types, on the other hand, are mutable data structures such as objects and arrays that comprise collections of data. When reference types get assigned to a variable, they store a link or reference to their location in memory, and not an actual copy of their values, hence their name.

var primitiveType = 'primitiveType';
var primitiveTypeCopy = 'primitiveType';
console.log(primitiveType === primitiveTypeCopy); //true
var referenceType = [1,2,3];
var referenceTypeCopy = [1,2,3];
console.log(referenceType === referenceTypeCopy); //false

Variables

Variables are data containers capable of referencing or representing any piece of information or data type with a simple identifier. They can store primitive data types as well as reference data types. They can also store expressions, which are strings of data that can be evaluated down to a single value.

var primitiveTypeString = 'primitiveTypeString';
var primitiveTypeNumber = 576;
var referenceTypeArray = ['primitiveTypeString',576];
var referenceTypeObject = 
{primitiveTypeString:'primitiveTypeString', 
primitiveTypeNumber:576};
var expression = primitiveTypeNumber + primitiveTypeNumber;

Variables can be declared, that is, given a name, and have data assigned to them, which means that the data gets stored into the variable, so it can be referenced by it through the use of the name we give the variable in its declaration.

var primitiveTypeString; //Declaration
primitiveTypeString = 'primitiveTypeString'; //Assignation 

Functions

A function is a sequence of program instructions that performs a specific task and is packed as a reusable unit. Functions can take in a set of values called arguments, perform a series of calculations or tasks with them and return any kind of data type or value as result of those operations.

The use of functions involves two basic steps: Declaration and invocation. In the declaration step we define a footprint of the function that contains all the necessary parts for it to work and be reused; that is an identifier, an optional set of variables called parameters that will be given a value when the function is invoked, and a set of instructions or statements involving variables declared as parameters or other variables accessible to the function. In order to invoke the function we use its identifier followed by a set of arguments that will supply a value to the parameters that were defined during the declaration of the function. We can also pass functions as values by referencing them without parentheses in order to obtain the body of the function instead of the value that they return.

function functionIdentifier(parameter1, parameter2){
   return parameter1 + parameter2
}; //Declaration
functionIdentifier(1,2); //invocation (returns 3)
var functionAsValue = functionIdentifier //Function assigned as 
value. When used without parentheses we get the body of the function
instead of its return value, as if we did this:
var functionAsValue = function functionIdentifier(parameter1, 
parameter2){
   return parameter1 + parameter2
}

Scope

Scope is the execution context through which a variable can be accessed. It defines accessibility regions within our code in which variables can be used, thus providing a mechanism to restrict access to variables depending on where they’re declared. This mechanism operates based on a hierarchical system of nested levels defined by either functions or blocks, and it establishes that every inner level can access the outer levels, but not the other way around; this is known as the scope chain or lexical scope.

function functionLevel1(){ //can only access varLevel1
   var varLevel1;
   function functionLevel2(){ //can access varLevel2 and varLevel1
      var varLevel2
   }
}

There are two types of scopes in Javascript: Function scope and block scope. Function scope can be set by declaring variables within a function using the keyword ‘var’, and it allows those variables to be accessed all across the functions in which they are declared. Block scope can be defined with the use of the keyword ‘let’ in variables declared inside a curly brackets block, and it restricts the access of those variables to code written within the block where the variable was declared.

var global //global scope
function bar(){
var functionScope //function scope
}
{let blockScope} //Block Scope

Closure

Closure is a mechanism by which a nested function can retain access to the variables within its lexical scope despite being invoked in a different execution context, even after the outer function that contains it has returned it. It can also be described as a reusable unit that encompasses an inner function packed along with the variables it had access to in the time of being declared.

We can see closure in action by declaring a function inside another function and return it, then we instantiate it into a variable so we can gain access to the inner function and call it from a different execution context.

function functionLevel1(){
   var varLevel1 = 'varLevel1';
   return function functionLevel2(){
   console.log(varLevel1)
   }
}
var closure = functionLevel1() //functionLevel2 assigned to closure
closure() //logs 'varLevel1' functionLevel2 retains access to varLevel1 in a different execution context

Objects

Objects are data structures whose elements consist of an identifier called key followed by any type of value, including primitives, functions and other reference types such as arrays or other objects. These key-value pairs are called methods when they store functions and properties when they store any other value, and they can be accessed with dot or square bracket notation.

var objectLiteral = {
   prop : 'value', //property
   meth : function methFunction(){} //method
}
var propAccessDot = objectLiteral.prop //property access dot notation
var propAccessBracket = objectLiteral[prop] //property access square bracket notation
var methAccessDot = objectLiteral.meth() //method access dot notation
var methAccessBracket = objectLiteral[method]() //method access square bracket notation

Objects are multidimensional, meaning they can be nested inside one another across multiple levels and they can be created with literal syntax, constructor functions, factory functions, the JavaScript method Object.create or with classes.

var objectLiteral = {property1 : 'value1', property2 : 'value2'} //Literal syntax
function objectConstructor(){
   this.property1 = 'value1',
   this.property2 = 'value2'
};
var objectConstructed = new objectConstructor; //Constructor function syntax
var objectFactory = function factory(){ //Factory function syntax
   return {property1 : 'value1', property2 : 'value2'}
}
var objectCreate = Object.create(object) //Object.create syntax
class Thing {
   constructor() {
      this.property1 = 'value1',
      this.property2 = 'value2'
   }
}
var objectClass = new Thing(); //Class syntax

Events

Events are messages used to trigger functions in response to user input or changes in the browser. With events and the functions they’re attached to, JavaScript can access and manipulate HTML elements through user interaction.

Events can be defined inline as HTML attributes or in the JavaScript code as either properties of HTML element objects or arguments of the addEventListener method.

<button onclick="document.getElementById('demo').innerHTML = Date()">The time is?</button> //Inline onclick event defined as HTML attribute
document.getElementById(id).onclick = function(){code} //onclick event defined as HTML element object property
document.getElementById("myBtn").addEventListener("click", displayDate); //onclick event defined as parameter of the addEventListener method

Context

In JavaScript every function is invoked within the context of an object, so the context of a function declared and invoked in the global scope is the global window object, and the context of a function declared as the method of an object and invoked through dot notation is that same object.

We can retrieve the context of a function through the keyword this, as well as change it explicitly with the Function.call method.

function globalContext(){
   return this // returns the global window object
}
var objectContextVar = {
   objectContextMeth : function objectContextFunction(){
   return this // returns objectContextVar
   }
}
objectContextVar.objectContextMeth() // returns objectContextVar
var anotherObjectContextVar = {}
objectContextVar.objectContextMeth.call(anotherObjectContextVar) // returns anotherObjectContextVar

Prototypes

Objects in JavaScript have a hierarchical relationship to each other that affects the way they share their respective properties. Every object in JavaScript is linked to a prototype object from which it gets an additional set of properties. This creates a multilevel structure of linked objects called prototype chain in which the lower level objects can access the properties of all the objects above them, but not the other way around.

var subObject = {}
console.log(Object.getPrototypeOf(subObject)) //logs Object
var subObject = []
console.log(Object.getPrototypeOf(subObject)) //logs Array
var subObject = 'string'
console.log(Object.getPrototypeOf(subObject)) //logs String

This linkage of objects is pre defined in Javascript to a certain extent, but it can also be extended and leveraged explicitly through the use of the Object.create method. We can get the prototype of an object with the Object.getPrototypeOf method and the __proto__ property of the sub object.

var proto = {}
var subObject = Object.create(proto)
console.log(Object.getPrototypeOf(subObject)) //logs proto
console.log(subObject.__proto__) //logs proto

Inheritance

Inheritance is a mechanism through which objects pass their properties down to other objects. JavaScript offers two different approaches to inheritance: pseudo - classical inheritance and prototypal inheritance. The first approach is based on classical concepts such as classes and constructor functions, whereas the second is based on the delegation of properties through the prototype chain.

//Pseudo - classical inheritance with constructor function
function construct(){this.prop = 'value'}
var heir = new construct
console.log(heir.prop) //logs 'value'

//Pseudo - classical inheritance with class syntax
class inheritor {
   constructor() {
   this.prop = 'value';
   }
}
var heir = new inheritor;
console.log(heir.prop) //logs 'value'

//Prototypal inheritance
var inheritor = {prop:'value'};
var heir = Object.create(inheritor);
console.log(heir.prop) //logs 'value'