DSA Javascript

Mastering JavaScript Fundamentals: Building 🏗️ a Strong Foundation for Data 🔡 Structures 🏛️

Israel

--

Introduction

JavaScript serves as a powerful programming language for building dynamic web applications. To gain a competitive edge in learning and implementing data structures, it is essential to grasp the core concepts and fundamentals of JavaScript. In this comprehensive guide, we will delve into JavaScript’s foundational elements, including variables, data types, control flow, loops, arrays, objects, functions, scope, and more.

By exploring both built-in and custom data structures and learning efficient algorithms, you will develop a strong foundation for effectively working with data. Throughout the article, we will provide code snippets and practical examples to reinforce your understanding and showcase real-world applications of JavaScript data structures.

Table of Content

  1. Introduction to JavaScript Fundamentals
  2. Understanding Variables and Data Types
  3. Exploring Control Flow and Loops
  4. Working with Arrays and Objects
  5. Essential Functions and Scope Concepts
  6. Leveraging JavaScript Built-in Data Structures
  7. Implementing Custom Data Structures in JavaScript
  8. Efficient Algorithms and Data Manipulation Techniques
  9. Putting It All Together: Practical Examples and Applications.
  10. Conclusion

This one is a long ride 🚗.. Regardless let’s get right on it…

1. Understanding Variables and Data Types:

JavaScript provides a flexible and dynamic approach to working with variables and different data types. In this section, we will explore how to declare and initialize variables, as well as understand primitive and complex data types in JavaScript. We will also delve into JavaScript’s dynamic typing system, which allows variables to hold values of different types during runtime.

Declaring and Initializing Variables:

In JavaScript, variables are declared using the var, let, or const keyword. Here’s an example:

// Declaring variables
var message;
let count;
const PI = 3.14159;

// Initializing variables
message = "Hello, World!";
count = 10;

In the above code snippet, we declare three variables: message, count, and PI. We initialize message with a string value, count with a numeric value, and PI with a constant value.

Exploring Primitive Data Types:

JavaScript has several primitive data types, including strings, numbers, booleans, null, and undefined. Here are examples of each:

// String
var name = "John";

// Number
var age = 25;

// Boolean
var isStudent = true;

// Null
var noValue = null;

// Undefined
var emptyValue;

In the code snippet above, we declare variables representing different primitive data types. name holds a string value, age holds a numeric value, isStudent holds a boolean value, noValue holds the null value, and emptyValue is declared but not assigned a value, resulting in undefined.

Working with Complex Data Types:

JavaScript also provides complex data types, namely arrays and objects. Let’s explore how to work with them:

Utilizing JavaScript’s Dynamic Typing System:

JavaScript employs dynamic typing, which means variables can hold values of different types during runtime. Let’s see an example:

var x = 10;
console.log(x); // Output: 10

x = "Hello";
console.log(x); // Output: "Hello"

x = true;
console.log(x); // Output: true

In the above code snippet, the variable x initially holds a numeric value of 10. However, we can later assign it a string value and then a boolean value. JavaScript allows this flexibility due to its dynamic typing nature.

2. Exploring Control Flow and Loops:

Control flow and loops are fundamental concepts in JavaScript that allow you to execute different blocks of code based on conditions and repeat code execution multiple times.

Conditional Statements: if-else and switch-case:

The if-else statement allows you to execute different blocks of code based on a condition. Here’s an example:

var age = 18;

if (age >= 18) {
console.log("You are eligible to vote.");
} else {
console.log("You are not eligible to vote yet.");
}

In the above code snippet, the condition age >= 18 is evaluated. If it’s true, the code inside the if block will be executed; otherwise, the code inside the else block will be executed.
The switch-case statement provides a way to perform different actions based on different values of a variable. Here’s an example:

var day = "Monday";

switch (day) {
case "Monday":
console.log("Today is Monday.");
break;
case "Tuesday":
console.log("Today is Tuesday.");
break;
default:
console.log("Today is neither Monday nor Tuesday.");
}

In the above code snippet, the value of the day variable is compared against different cases. If a match is found, the corresponding code block will be executed. The break statement is used to exit the switch statement after executing a case.

3. Iteration and Looping Techniques:

Iteration allows you to repeat a block of code multiple times. JavaScript provides different looping techniques to achieve this:

The for loop is commonly used when you know the number of iterations beforehand. Here’s an example:

for (var i = 1; i <= 5; i++) {
console.log("Iteration " + i);
}

In the above code snippet, the loop iterates five times, printing the message "Iteration" along with the current iteration number.

The while loop repeats a block of code as long as a specified condition is true. Here’s an example:

var i = 1;

while (i <= 5) {
console.log("Iteration " + i);
i++;
}

In the above code snippet, the loop iterates until the condition i <= 5 becomes false. The variable i is incremented in each iteration.

The do-while loop is similar to the while loop, but it always executes the code block at least once, even if the condition is initially false. Here’s an example:

var i = 1;

do {
console.log("Iteration " + i);
i++;
} while (i <= 5);

In the above code snippet, the code block is executed once, and then the condition i <= 5 is checked. If it’s true, the loop continues, and if it’s false, the loop terminates.

Breaking and Continuing Loop Execution:

In JavaScript, you can control the flow of loops using the break and continue statements.
The break statement is used to exit a loop prematurely. It allows you to terminate the loop execution based on a certain condition. Here’s an example:

for (var i = 1; i <= 10; i++) {
if (i === 6) {
break;
}
console.log("Iteration " + i);
}

In the above code snippet, the loop iterates from 1 to 10. However, when the value of i becomes 6, the break statement is encountered, and the loop is terminated immediately.
The continue statement is used to skip the current iteration and move to the next iteration of a loop. It allows you to skip certain code blocks within the loop based on a condition. Here’s an example:

for (var i = 1; i <= 5; i++) {
if (i === 3) {
continue;
}
console.log("Iteration " + i);
}

In the above code snippet, when i is equal to 3, the continue statement is encountered. As a result, the code block following the continue statement is skipped for that iteration, and the loop continues with the next iteration.

4. Working with Arrays and Objects:

Arrays and objects are powerful data structures in JavaScript that allow you to store and manipulate collections of data. In this section, we will explore how to create and manipulate arrays, access their elements, work with object properties and methods, and iterate over both arrays and objects.

Creating and Manipulating Arrays:

In the above code snippet, we create an array called numbers containing a sequence of integers. We can access array elements using index notation, modify specific elements by assigning new values, and add or remove elements using built-in array methods like push() and pop().

Accessing Array Elements and Performing Common Operations:

Arrays provide various methods and operations to access and manipulate their elements.

In the above code snippet, we work with an array of fruits. We can obtain the length of the array using the length property, check if a specific element exists using the includes() method, find the index of an element using the indexOf() method, and join the array elements into a string using the join() method.

Understanding Object Properties and Methods:

Objects in JavaScript consist of key-value pairs and allow you to organize related data. They can have properties and methods associated with them.

// Creating an object
var person = {
name: "John",
age: 30,
occupation: "Engineer",

// Method
introduce: function() {
console.log("Hi, I'm " + this.name + ". I'm " + this.age + " years old.");
}
};

// Accessing object properties
console.log(person.name); // Output: "John"

// Calling object methods
person.introduce(); // Output: "Hi, I'm John. I'm 30 years old."

In the above code snippet, we create an object called person with properties such as name, age, and occupation. Objects can also contain methods, which are functions associated with the object. We can access object properties using dot notation and call object methods using parentheses.

Iterating over Objects and Arrays:

Iterating over objects and arrays allows you to perform operations on each element or property.

// Iterating over an array
var numbers = [1, 2, 3, 4, 5];
numbers.forEach(function(number) {

console.log(number);
});

// Iterating over an object
var person = {
name: "John",
age: 30,
occupation: "Engineer"
};

for (var key in person) {
console.log(key + ": " + person[key]);
}



In the above code snippets, we demonstrate how to iterate over an array and an object. For arrays, we use the `forEach()` method, which accepts a callback function to perform an operation on each element. For objects, we use a `for...in` loop to iterate over the object's properties. Inside the loop, we access the property values using bracket notation (`person[key]`) and log them to the console.

By understanding how to create and manipulate arrays, access their elements, work with object properties and methods, and iterate over both arrays and objects, you can effectively handle and process data in your JavaScript applications. These concepts are foundational to working with complex data structures and implementing various algorithms and operations.

5. Essential Functions and Scope Concepts:

Functions are a fundamental building block in JavaScript that allow you to group and organize reusable blocks of code. In this section, we will explore key concepts related to functions, including defining and invoking functions, working with function parameters and return values, understanding function scope and hoisting, and utilizing closures for encapsulation and data privacy.

Defining and Invoking Functions:

Functions in JavaScript are defined using the function keyword followed by the function name and a pair of parentheses. Here’s an example of defining and invoking a function:

// Defining a function
function greet() {
console.log("Hello, world!");
}

// Invoking a function
greet(); // Output: "Hello, world!"

In the above code snippet, we define a function called greet that logs a greeting message to the console. We invoke the function using parentheses after the function name.

Function Parameters and Return Values:

Functions can accept parameters, which are placeholders for values that can be passed when invoking the function. Functions can also return values using the return statement. Here’s an example:

// Function with parameters and return value
function add(a, b) {
return a + b;
}

// Invoking the function with arguments
var result = add(2, 3);
console.log(result); // Output: 5

In the above code snippet, we define a function called add that takes two parameters (a and b). Inside the function, we use the return statement to return the sum of a and b. We then invoke the function with arguments (2 and 3) and assign the returned value to a variable called result. Finally, we log the result to the console.

Understanding Function Scope and Hoisting:

Function scope refers to the visibility and accessibility of variables within a function. Variables declared within a function are locally scoped and cannot be accessed outside the function. JavaScript also has the concept of hoisting, which allows you to use a variable or function before it is declared. Here’s an example:

function multiply(a, b) {
var result = a * b; // Locally scoped variable

console.log(result); // Output: 6

// Hoisted function
function double(num) {
return num * 2;
}

console.log(double(result)); // Output: 12
}

multiply(2, 3);

In the above code snippet, we define a function called multiply that multiplies two numbers and stores the result in a locally scoped variable called result. We then log the result to the console. Inside the function, we also define another function called double, which is hoisted and can be used before its actual declaration. We invoke the double function with the result variable as an argument and log the returned value to the console.

Utilizing Closures for Encapsulation and Data Privacy:

Encapsulation and Data Privacy:
Closures are a powerful concept in JavaScript that allows functions to retain access to variables from their parent scope even after the parent function has finished executing. This enables encapsulation and data privacy. Here’s an example:

function createCounter() {
var count = 0;

function increment() {
count++;
console.log(count);
}

return increment;
}

var counter = createCounter();
counter(); // Output: 1
counter(); // Output: 2

In the above code snippet, we define a function called createCounter that creates a counter using a locally scoped variable count. Inside createCounter, we define an inner function called increment that increments the count variable and logs its value to the console. The increment function is then returned from the createCounter function.

When we invoke createCounter and assign the returned function to the counter variable, we create a closure. The closure retains access to the count variable even after the createCounter function has finished executing. Subsequent invocations of the counter function increment the count variable and log the updated value.

6. Leveraging JavaScript Built-in Data Structures:

JavaScript provides built-in data structures such as Set and Map that offer powerful functionality for storing and manipulating data. In this section, we will explore how to utilize these data structures and perform common operations on them.

Utilizing Set:

A Set is a collection of unique values, where each value can only appear once. You can use the Set data structure to store and manage unique elements efficiently.

// Creating a Set
const set = new Set();

// Adding elements to the Set
set.add("apple");
set.add("banana");
set.add("orange");

// Checking if an element exists in the Set
console.log(set.has("banana")); // Output: true

// Getting the size of the Set
console.log(set.size); // Output: 3

// Removing an element from the Set
set.delete("apple");

// Iterating over the Set
set.forEach((value) => {
console.log(value);
});

In the above code snippet, we create a Set using the new Set() constructor. We can add elements to the Set using the add() method, check if an element exists using the has() method, and remove an element using the delete() method. The size property gives us the number of elements in the Set. We can iterate over the Set using the forEach() method.

Utilizing Map:

A Map is a collection of key-value pairs, where each key can only appear once. It provides an efficient way to store and retrieve data using a specific key.

// Creating a Map
const map = new Map();

// Adding key-value pairs to the Map
map.set("name", "John");
map.set("age", 30);
map.set("occupation", "Engineer");

// Getting a value from the Map
console.log(map.get("age")); // Output: 30

// Checking if a key exists in the Map
console.log(map.has("occupation")); // Output: true

// Getting the size of the Map
console.log(map.size); // Output: 3

// Removing a key-value pair from the Map
map.delete("age");

// Iterating over the Map
map.forEach((value, key) => {
console.log(`${key}: ${value}`);
});

In the above code snippet, we create a Map using the new Map() constructor. We can add key-value pairs to the Map using the set() method, retrieve a value using the get() method, check if a key exists using the has() method, and remove a key-value pair using the delete() method. The size property gives us the number of key-value pairs in the Map. We can iterate over the Map using the forEach() method.

7. Implementing Custom Data Structures in JavaScript:

In JavaScript, you have the flexibility to design and implement custom data structures to suit your specific needs. In this section, we will explore the implementation of popular data structures such as linked lists, stacks, and queues. We will also discuss how to add functionality to these custom data structures.

Linked Lists:

A linked list is a linear data structure where each element, called a node, contains a reference to the next node. It provides efficient insertion and deletion operations.

// Linked List Node
function Node(value) {
this.value = value;
this.next = null;
}

// Linked List
function LinkedList() {
this.head = null;
this.tail = null;
}

// Adding a node to the linked list
LinkedList.prototype.add = function (value) {
const newNode = new Node(value);

if (this.head === null) {
this.head = newNode;
this.tail = newNode;
} else {
this.tail.next = newNode;
this.tail = newNode;
}
};

// Displaying the linked list
LinkedList.prototype.display = function () {
let currentNode = this.head;

while (currentNode !== null) {
console.log(currentNode.value);
currentNode = currentNode.next;
}
};

// Creating and using the linked list
const linkedList = new LinkedList();
linkedList.add(10);
linkedList.add(20);
linkedList.add(30);
linkedList.display();

In the above code snippet, we define a Node function constructor to create individual nodes of the linked list. The LinkedList function constructor initializes the head and tail pointers of the linked list. The add method adds a new node to the linked list by updating the next reference of the current tail node. The display method iterates over the linked list and logs the values of each node.

Stacks:

A stack is an ordered collection of elements where elements are added and removed from the same end, known as the top. It follows the Last-In-First-Out (LIFO) principle.

// Stack
function Stack() {
this.items = [];
}

// Adding an element to the stack
Stack.prototype.push = function (element) {
this.items.push(element);
};

// Removing the top element from the stack
Stack.prototype.pop = function () {
if (this.items.length === 0) {
return null;
}
return this.items.pop();
};

// Displaying the stack
Stack.prototype.display = function () {
console.log(this.items);
};

// Creating and using the stack
const stack = new Stack();
stack.push(10);
stack.push(20);
stack.push(30);
stack.display();
stack.pop();
stack.display();

In the above code snippet, we define a Stack function constructor. The push method adds an element to the top of the stack using the push function of the underlying array. The pop method removes and returns the top element from the stack using the pop function of the array. The display method logs the elements of the stack.

Queues:

A queue is an ordered collection of elements where elements are added to one end, known as the rear, and removed from the other end, known as the front. It follows the First-In-First-Out (FIFO) principle.

// Queue
function Queue() {
this.items = [];
}

// Adding an element to the queue
Queue.prototype.enqueue = function (element) {
this.items.push(element);
};

// Removing the front element from the queue
Queue.prototype.dequeue = function () {
if (this.items.length === 0) {
return null;

}
return this.items.shift();
};

// Displaying the queue
Queue.prototype.display = function () {
console.log(this.items);
};



// Displaying the queue
Queue.prototype.display = function () {
console.log(this.items);
};

// Creating and using the queue
const queue = new Queue();
queue.enqueue(10);
queue.enqueue(20);
queue.enqueue(30);
queue.display();
queue.dequeue();
queue.display();


In the above code snippet, we define a `Queue` function constructor. The `enqueue` method adds an element to the rear of the queue using the `push` function of the underlying array. The `dequeue` method removes and returns the front element from the queue using the `shift` function of the array. The `display` method logs the elements of the queue.

By implementing custom data structures such as linked lists, stacks, and queues in JavaScript, you can effectively manage and manipulate data in a way that suits your application's requirements. These examples demonstrate the basic functionality of each data structure, but you can expand upon them to add more advanced features or modify them to fit your specific needs.

8. Efficient Algorithms and Data Manipulation Techniques:

Understanding and implementing efficient algorithms and data manipulation techniques is crucial for developing performant applications. In this section, we will explore essential algorithms such as sorting and searching, discuss recursion as a powerful technique, analyze time and space complexity, and apply efficient data manipulation techniques.

Sorting:

Sorting is the process of arranging elements in a specific order. There are various sorting algorithms available, but one commonly used algorithm is the Bubble Sort algorithm.

In the above code snippet, we implement the Bubble Sort algorithm, which repeatedly compares adjacent elements and swaps them if they are in the wrong order. This process is repeated until the entire array is sorted in ascending order. The sorted array is then returned.

Searching:

Searching involves finding a specific element or value within a collection. One commonly used searching algorithm is the Binary Search algorithm.

// Binary Search
function binarySearch(arr, target) {
let left = 0;
let right = arr.length - 1;

while (left <= right) {
const mid = Math.floor((left + right) / 2);

if (arr[mid] === target) {
return mid;
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}

return -1;
}

// Usage
const sortedArray = [1, 2, 3, 5, 8];
const target = 3;
const index = binarySearch(sortedArray, target);
console.log(index); // Output: 2

In the above code snippet, we implement the Binary Search algorithm, which works on a sorted array. It repeatedly divides the search space in half by comparing the middle element with the target value. If the middle element is equal to the target, the index is returned. If the middle element is smaller than the target, the search space is reduced to the right half. If the middle element is larger than the target, the search space is reduced to the left half. This process continues until the target is found or the search space is exhausted.

Recursion:

Recursion is a technique where a function calls itself to solve a problem by breaking it down into smaller subproblems. One classic example is the factorial function.

// Factorial
function factorial(n) {
if (n === 0 || n === 1) {
return 1;
}

return n * factorial(n - 1);
}

// Usage
const num = 5;
const result = factorial(num);
console.log(result); // Output: 120

In the above code snippet, we define the factorial function using recursion. The factorial of a non-negative integer n is the product of all positive integers less than or equal to n. The recursive factorial function breaks down the problem into smaller subproblems by calling itself with a reduced value of n until it reaches the base case of n being 0 or 1. The function then returns the product of n and the factorial of n-1.

Time and Space Complexity:

Analyzing the time and space complexity of algorithms helps us understand their efficiency. Time complexity measures how the runtime of an algorithm grows with the input size, while space complexity measures the memory usage.

For example, the time complexity of the Bubble Sort algorithm is O(n^2), indicating that the number of operations grows quadratically with the input size. The space complexity is O(1) because it uses a constant amount of additional memory.

The time complexity of the Binary Search algorithm is O(log n) since it halves the search space with each iteration. The space complexity is O(1) as well.

Efficient Data Manipulation Techniques:

Efficiently manipulating data involves using appropriate built-in methods and techniques provided by JavaScript. Here are a few examples:

In the above code snippets, we demonstrate some efficient data manipulation techniques. The map method applies a provided function to each element of an array and returns a new array with the results. The filter method creates a new array with elements that pass a specific condition. The split method splits a string into an array of substrings based on a specified delimiter, and the join method combines the elements of an array into a string using a specified separator.

9. Putting It All Together: Practical Examples and Applications

In this section, we will explore practical examples and applications where we can apply our knowledge of JavaScript data structures, JavaScript fundamentals, and coding challenges.

Applying JavaScript Data Structures to Real-World Scenarios:

a. Using a Stack for Browser History:
A stack data structure can be used to implement a browser history functionality. Here’s an example:

import React, { useState } from 'react';

const Stack = () => {
const [items, setItems] = useState([]);

const push = (item) => {
setItems((prevItems) => [...prevItems, item]);
};

const pop = () => {
if (isEmpty()) {
return null;
}
return setItems((prevItems) => {
const newItems = [...prevItems];
return newItems.pop();
});
};

const isEmpty = () => {
return items.length === 0;
};

return (
<div>
<button onClick={() => push('https://example.com')}>Push</button>
<button onClick={() => pop()}>Pop</button>
</div>
);
};

export default Stack;

In the above code snippet, we import the necessary dependencies from React, including the useState hook. We define a functional component Stack and use the useState hook to initialize the items state with an empty array.

We rewrite the push function to update the state by spreading the previous items and adding the new item to the end of the array using the spread operator.

The pop function checks if the stack is empty using the isEmpty function. If it's not empty, it creates a new array of items by spreading the previous items, then calls the pop method on the new array. Finally, it updates the state with the new array.

The isEmpty function checks if the length of the items array is equal to 0.

In the JSX part, we render two buttons, one for pushing a new item and another for popping an item. Clicking the buttons will trigger the corresponding functions.

This functional component provides similar functionality to the original class component but follows the functional component pattern and utilizes the useState hook for state management.

Note: To use this functional component, make sure you have React and the necessary dependencies set up in your project.

Using a Map for User Preferences:

A map data structure can be used to store and retrieve user preferences. Here’s an example:

const userPreferences = new Map();

// Storing user preferences
userPreferences.set('theme', 'dark');
userPreferences.set('language', 'en');
userPreferences.set('notifications', true);

console.log(userPreferences.get('theme')); // Output: dark
console.log(userPreferences.get('notifications')); // Output: true

In the above code snippet, we create a map called userPreferences to store various user preferences. The set method is used to associate a preference key with its corresponding value. The get method retrieves the value associated with a specific key.

Building Interactive Applications Using JavaScript Fundamentals:

a. Creating a To-Do List with Array Manipulation: Using JavaScript arrays, we can create a simple to-do list application. Here’s an example:

const todoList = [];

// Adding items to the to-do list
function addTodoItem(item) {
todoList.push(item);
}

// Removing items from the to-do list
function removeTodoItem(item) {
const index = todoList.indexOf(item);
if (index !== -1) {
todoList.splice(index, 1);
}
}

addTodoItem('Buy groceries');
addTodoItem('Clean the house');
addTodoItem('Pay bills');

console.log(todoList); // Output: ["Buy groceries", "Clean the house", "Pay bills"]

removeTodoItem('Clean the house');

console.log(todoList); // Output: ["Buy groceries", "Pay bills"]

In the above code snippet, we define functions to add and remove items from a to-do list. The addTodoItem function adds an item to the todoList array using the push method. The removeTodoItem function removes an item from the todoList array using the indexOf method to find the index of the item and the splice method to remove it.

Solving Coding Challenges and Exercises with Data Structures:

a. Finding the Sum of an Array:
Let’s solve a coding challenge where we need to find the sum of all elements in an array:

function sumArray(arr) {
let sum = 0;
for (let i = 0; i < arr.length; i++) {

sum += arr[i];
}
return sum;
}

const numbers = [1, 2, 3, 4, 5];
console.log(sumArray(numbers)); // Output: 15

In the above code snippet, we define a function `sumArray` that takes an array as input. We initialize a variable `sum` to 0 and use a `for` loop to iterate over each element of the array. Inside the loop, we add each element to the `sum` variable. Finally, we return the `sum` as the result.

By solving coding challenges and exercises, we can apply our knowledge of data structures and JavaScript fundamentals to solve real-world problems efficiently and effectively.

Conclusion:
Understanding the core concepts of JavaScript, such as variables and data types, control flow and loops, arrays and objects, functions and scope, built-in data structures, efficient algorithms, and data manipulation techniques, provides a solid foundation for developing JavaScript applications.

By applying these concepts and techniques to practical examples and scenarios, building interactive applications, and solving coding challenges, you can enhance your JavaScript skills and become a more proficient developer.

Remember to continue practicing and exploring JavaScript's vast ecosystem to deepen your understanding and stay up to date with the latest advancements.

10. Conclusion:

By mastering the fundamental concepts of JavaScript, including variables, data types, control flow, arrays, objects, functions, and scope, along with leveraging built-in and custom data structures, you have laid a solid foundation for effectively working with data. Applying efficient algorithms and techniques will further enhance your ability to manipulate data and solve complex problems. Continued practice, exploration, and building practical applications will solidify your understanding and proficiency in JavaScript and data structures.

I hope this revised version provides a clear and organized explanation of each point with accompanying code snippets. Remember to further explore each topic to gain a deeper understanding and apply these concepts in real-world scenarios.

The best way to know this perfectly is by actually getting your hands dirty. Practice as much as you can.

Drop a like and comment if you find this helpful. Gracias 🙏

--

--

Israel

I'm Isreal a Frontend Engineer with 4+ experience in the space . My love to profer solutions led me to being a technical writer. I hope to make +ve impact here.