JavaScript Data Types
- Primitive Data type
- boolean: true, false
- number
- string
- null: empty
- undefined: no value
- Non-Primitive Data type
- object
const , let vs var
const & let are part of ES6 release, it solves the issue of variable hoisting caused by lexical scoping. const and let are defined as block scoped vs var is defined in lexical scope.
function variableHoisting () {
if (true) {
var num = 5;
}
return num;
}
console.log(variableHoisting()); // expected output: 5
// Behind the scene declaration of num
function variableHoisting () {
var num;
if (true) {
num = 5;
}
return num;
}
In this scenario ‘num’ is declared in lexical scope and variable is hoisted. In case of let variable declaration ‘num’ is block scoped and it will return not defined.
function variableHoisting () {
if (true) {
let num = 5;
}
return num;
}
console.log(variableHoisting()); // expected output: num is not defined
‘let’ will mainly be used of primitive values and ‘const’ is used for constant values or objects. Primitive const variable declaration can not be reassigned a new value. Non-primitive datatype declared as const can be modified using methods such as push, concat etc.
Pass By Value vs Pass By Reference
//Pass by value example on primitive datatypes
let variable1 = 1;
let variable2 = variable1;
variable2++;
console.log(variable1, ' - ', variable2);
// expected output: 1 ' - ' 2
//Value of variable1 wont be modified as it was passed as value
//Pass by reference example on non-primitive datatypes
const array1 = ['orange'];
const array2 = array1;
const array3 = [...array1]; //pass by value using spread operator
console.log(array3); //expected output: [ 'orange' ]
array2.push('apple');
console.log(array1, ' - ', array2);
//expected output: [ 'orange', 'apple' ] ' - ' [ 'orange', 'apple' ]
//array1 value is updated whenever array2 is modified as it was passed by reference.
map(), filter(), reduce()
The map()
method creates a new array populated with the results of calling a provided function on every element in the calling array.
const numbers = [1, 2, 3, 10, 20, 30];
const mappedNumbers = numbers.map((number) => number + 1);
console.log(mappedNumbers);
//expected output: [ 2, 3, 4, 11, 21, 31 ]
The filter()
method creates a new array with all elements that pass the test implemented by the provided function.
const numbers = [1, 2, 3, 10, 20, 30];
const filteredNumbers = numbers.filter((number) => number < 10);
console.log(filteredNumbers);
//expected output: [ 1, 2, 3 ]
The easiest-to-understand case for reduce()
is to return the sum of all the elements in an array
const numbers = [1, 2, 3, 10, 20, 30];
const reduceNumbers = numbers.reduce((total, current) => {
return total += current;
}, 0);
console.log(reduceNumbers); //expected output: 66
Falsey Value
When evaluated as boolean returns false.
const example1 = undefined;
const example2 = null;
const example3 = NaN;
const example4 = 0;
const example5 = '';
const example6 = false;
console.log(!!example1); // expected output: false
console.log(!!example2); // expected output: false
console.log(!!example3); // expected output: false
console.log(!!example4); // expected output: false
console.log(!!example5); // expected output: false
console.log(!!example6); // expected output: false
this
access the enclosing lexical context.
const exampleObj = {
first: 'John',
last: 'Doe',
fullName () {
return `${this.first} ${this.last}`;
}
};
console.log(exampleObj.fullName());
// expected output: John Doe
Arrow Functions
An arrow function expression is a compact alternative to a traditional function expression. Does not have its own bindings to this or super, and should not be used as methods.
const numbers = [
'one',
'two',
'three',
'four'
];
console.log(numbers.map(number => number.length));
// expected output: Array [3, 3, 5, 4]
= & == & ===
= is assignment
== check equality
=== check equality and type check
const num1 = 5;
const num2 = '5';
console.log(num1 == num2); // expected output: true
console.log(num1 === num2); // expected output: false
Coercion
Type coercion is the automatic or implicit conversion of values from one data type to another
const total = 2 + 3 + '7';
console.log(total); // expected output: 57
console.log(typeof total); // expected output: string
typeof
checks the type of data
console.log(typeof 20 === 'number'); // expected output: true
console.log(typeof NaN === 'number'); // expected output: true
console.log(typeof `template literal` === 'string'); // expected output: true
console.log(typeof '1' === 'string'); // expected output: true
console.log(typeof true === 'boolean'); // expected output: true
console.log(typeof undefined === 'undefined'); // expected output: true
console.log(typeof {
a: 1
} === 'object'); // expected output: true
console.log(typeof [1, 2, 4] === 'object'); // expected output: true
console.log(Array.isArray([1, 2, 4])); // expected output: true
console.log(Array.isArray({})); // expected output: false
console.log(typeof new Date() === 'object'); // expected output: true
console.log(typeof /regex/ === 'object'); // expected output: true
console.log(null instanceof Object); // expected output: false
console.log(typeof null); // expected output: object
console.log({} instanceof Object); // expected output: true
console.log(typeof function () {} === 'function'); // expected output: true
console.log(typeof Math.sin === 'function'); // expected output: true
delete
The JavaScript delete
operator removes a property from an object.
const Employee = {
firstname: 'John',
lastname: 'Doe'
};
console.log(Employee.firstname);
// expected output: "John"
delete Employee.firstname;
console.log(Employee.firstname);
// expected output: undefined
Anonymous Functions
An anonymous function is a function without a name. When the function is being assigned to variable.
let showMe = function () {
console.log('Anonymous function');
};
showMe();
Callbacks
A callback is a function passed as an argument to another function. Also referred as higher order functions.
const originalArray = [1, 2, 3, 4, 5];
const outputArray = originalArray.map(add5);
// here add5 is callback function
console.log(outputArray);
// expected output: [ 6, 7, 8, 9, 10 ]
function add5 (val) {
return val + 5;
}
IIFE – Immediately Invoked Function Expression
A JavaScript function that runs as soon as it is defined.
(function () {
console.log('i am called, already!!');
})();
// expected output: i am called, already!!
Closures
A closure in simple words a function that returns a function by doing so it gives you access to an outer function’s scope from an inner function. Closures are created every time a function is created.
const add1 = (function () {
let counter = 0;
return function () {
counter++;
return counter;
}; // Anonymous function
})(); //iife
console.log(add1()); // expected output: 1
console.log(add1()); // expected output: 2
console.log(add1()); // expected output: 3
Destructuring Objects & Arrays
JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
//Array destructuring
const foo = ['one', 'two', 'three'];
const [red, yellow, green] = foo;
console.log(red); // expected output: "one"
console.log(yellow); // expected output: "two"
console.log(green); // expected output: "three"
//Object destructuring
const user = {
id: 1,
firstName:'John',
lastName: 'Doe'
};
const {id, firstName, lastName} = user;
console.log(id); // expected output: 1
console.log(firstName); // expected output: John
console.log(lastName); // expected output: Doe
Rest & Spread Operator
Rest operator puts the rest of some specific user-supplied values into a JavaScript array and spread syntax expands iterables into individual elements.
With Rest operator a function can be called with any number of arguments, no matter how it is defined.
function sumAll(...args) { // args is the name for the array
let sum = 0;
for (let arg of args) sum += arg;
return sum;
}
console.log( sumAll(1) ); // expected output: 1
console.log( sumAll(1, 2) ); // expected output: 3
console.log( sumAll(1, 2, 3) ); // expected output: 6
Spread syntax can be used when all elements from an object or array need to be included in a list of some kind. Can also be used to split string into character array.
let str = "Hello";
console.log( [...str] );
// expected output: [ H, e, l, l, o ]
Object Comparison
Objects are more difficult to compare because they are structured data unlike primitive values in javascript
const user1 = {
first: 'John',
last: 'Doe',
address: {
line1: 'some str',
}
};
const user2 = {
last: 'Doe',
first: 'John',
address: {
line1: 'some str',
}
};
console.log(user1 === user2); // expected output: false
// this returns false as user1 & user2 values are passed by reference so even though they have same values they are different object instances
One other way to compare two objects is by content comparison. Access the property name of both objects and compares their values. This could get really complicated for objects with unknown structures
function isSameObject (obj1, obj2) {
const props1 = Object.getOwnPropertyNames(obj1);
const props2 = Object.getOwnPropertyNames(obj2);
if (props1.length !== props2.length) {
return false;
}
for (const key of props1) {
const val1 = obj1[key];
const val2 = obj2[key];
const areObjects = isObject(val1) && isObject(val2);
if ((areObjects && !isSameObject(val1, val2)) || (!areObjects && val1 !== val2)) {
return false;
}
}
return true;
}
function isObject(object) {
return object != null && typeof object === 'object';
}
console.log(user1 === user2); // expected output: true
isSameObject method will perform a deep equality recursively meaning areObjects && !deepEqual(val1, val2)
indicates that as soon as the compared properties are objects, a recursive call starts to verify whether the nested objects are equal too.
keep dabbling…