JavaScript is a prototype-based language, which means that it uses prototypes to inherit properties and methods from one object to another. In JavaScript, objects can be linked to other objects, forming a prototype chain. Since JavaScript is a loosely typed language, you are not required to correctly predict the kind of data that will be kept in a variable. Dynamically typed languages like Python and JavaScript offer more flexibility, but they might lead to runtime errors due to unexpected type mismatches. On the other hand, statically typed languages are more verbose, which developers might sometimes find inconvenient, especially when rapid prototyping is required.
- Webkit developed by Apple (used by Safari, Chrome)
- Gecko developed by Mozila (used by Firefox)
- Blink developed by Google (Chrome and all other Chromium-based browsers, notably Microsoft Edge, Brave, Vivaldi, Samsung Internet and Opera)
-
Chakra written in c++ for microsoft used by Edge browser
-
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++. It is used in Chrome and in Node.js, among others. It implements ECMAScript and WebAssembly, and runs on Windows 7 or later, macOS 10.12+, and Linux systems that use x64, IA-32, ARM, or MIPS processors. V8 can run standalone, or can be embedded into any C++ application.
-
SpiderMonkey is Mozilla’s JavaScript and WebAssembly Engine, used in Firefox, Servo and various other projects. It is written in C++, Rust and JavaScript. You can embed it into C++ and Rust projects, and it can be run as a stand-alone shell. It can also be compiled to WASI; see our online demo.
-
JavaScriptCore written in Objective-c, used by Safari browser.(also called Nitro)
-
QuickJs is an embeddable JS engine written in C.
-
Hermes is a JavaScript engine optimized for fast start-up of React Native apps.
-
Duktape - embeddable Javascript engine with a focus on portability and compact footprint.
- Node.js is an open-source, cross-platform JavaScript runtime environment.
- Deno Next-generation JavaScript runtime .Secure by default .Native support for TypeScript and JSX .Testing, linting, formatting, and more out of the box .High performance async I/O with Rust and Tokio .Backwards compatible with Node.js and npm
- Bun At its core is the Bun runtime, a fast JavaScript runtime designed as a drop-in replacement for Node.js. It's written in Zig and powered by JavaScriptCore under the hood, dramatically reducing startup times and memory usage.
- LLRT LLRT (Low Latency Runtime) is a lightweight JavaScript runtime designed to address the growing demand for fast and efficient Serverless applications. LLRT offers up to over 10x faster startup and up to 2x overall lower cost compared to other JavaScript runtimes running on AWS Lambda. It's built in Rust, utilizing QuickJS as JavaScript engine, ensuring efficient memory usage and swift startup.
- txiki A tiny JavaScript runtime
ECMAScript Version | Release Year | Notable Features |
---|---|---|
ES1 | 1997 | Initial version of ECMAScript. |
ES2 | 1998 | Addition of try/catch statement, and method toLocaleString(). |
ES3 | 1999 | Introduction of new features like regular expressions, exceptions, and more robust error handling. |
ES5 | 2009 | Added 'strict mode', JSON support, getters and setters, and more array methods like forEach(), map(), and reduce(). |
ES6 / ES2015 | 2015 | Major update with significant additions including arrow functions, classes, template literals, let and const keywords, and more. |
ES7 / ES2016 | 2016 | Introduction of features like the exponentiation operator (** ) and Array.prototype.includes(). |
ES8 / ES2017 | 2017 | Added async/await, Object.values/Object.entries, String padding, and more. |
ES9 / ES2018 | 2018 | Introduced features like asynchronous iteration, Rest/Spread Properties, and Promise.prototype.finally(). |
ES10 / ES2019 | 2019 | Added features like Array.prototype.flat(), Array.prototype.flatMap(), String.prototype.trimStart()/trimEnd(), and optional catch binding. |
ES11 / ES2020 | 2020 | Introduced features like BigInt, Promise.allSettled(), String.prototype.matchAll(), and globalThis. |
ES12 / ES2021 | 2021 | Added features like String.prototype.replaceAll(), Numeric separators, Logical Assignment Operators, and Promise.any(). |
ES13 / ES2022 | 2022 | Proposed features include Array.prototype.groupBy(), Object.observe(), and more. |
javaScript transcompiler that is mainly used to convert ECMAScript 2015+ code into backwards-compatible JavaScript code that can be run by older JavaScript engines. It allows web developers to take advantage of the newest features of the language.
- peer-server-peer comunication
- protocol
WS
/WSS
- peer to peer comunication
- protocol
UDP
User Datagram Protocol (UDP) is a communications protocol for time-sensitive applications like gaming, playing videos, or Domain Name System (DNS) lookups.
- Core-js polyfills library.
- stdlib (/ˈstændərd lɪb/ "standard lib") is a standard library, with an emphasis on numerical and scientific computation, written in JavaScript (and C) for execution in browsers and in Node.js.
- RxJS A reactive programming library for JavaScript
- lodash
- moment
- async
- collect.js
- enquirer Stylish, intuitive and user-friendly prompts, for Node.js.
- chalk
- EsLint
- jsLint
- TypeScript is super-set of javascript.
- tsConfig
- Primitive The predefined data types provided by JavaScript language are known as primitive data types. Primitive data types are also known as in-built data types.
- String.
typeof 'hello world' // string;
- Number.
typeof 123 // number
- Bigint.
typeof 2n // bigint
- Boolean.
typeof true // boolean
- Undefined.
typeof undefined // undefined
- Null.
typeof null // object
- Symbol.
typeof Symbol('test') // symbol
- String.
- Non Primitive The data types that are derived from primitive data types of the JavaScript language are known as non-primitive data types. It is also known as derived data types or reference data types.
Mention some Standard built-in objects
- Value properties :These global properties return a simple value. They have no properties or methods.
globalThis
Infinity
NaN
undefined
- Fundamental objects :These objects represent fundamental language constructs.
Object
Function
Boolean
Symbol
- Numbers and Dates :These are the base objects representing numbers, dates, and mathematical calculations.
Number
BigInt
Math
Date
- Function properties : These global functions—functions which are called globally, rather than on an object—directly return their results to the caller.
eval()
isFinite()
isNaN()
parseFloat()
parseInt()
decodeURI()
encodeURI()
- Text processing :These objects represent strings and support manipulating them.
String
RegExp
- Indexed collections : These objects represent collections of data which are ordered by an index value.
- Keyed collections :These objects represent collections which use keys.
- Control abstraction objects :Control abstractions can help to structure code, especially async code (without using deeply nested callbacks, for example).
- Iterator
- AsyncIterator
- Promise
There are three status with in promise
pending
: initial state, neither fulfilled nor rejected.fulfilled
: meaning that the operation was completed successfully.rejected
: meaning that the operation failed.Promise<pending> .then(()=>// Promise<fulfilled>) .catch(()=> // Promise<rejected>) .finally(()=> // this is last code of block which always execute end of everything)
- Promise.all([]) : static method takes an
iterable
of promises as input and returns a singlePromise
.
Fulfills when all of the promises fulfill; rejects when any of the promises rejects.
- Promise.any([]): static method takes an
iterable
of promises as input and returns a singlePromise
.
Fulfills when any of the promises fulfills; rejects when all of the promises reject. Important Note You may compare
Promise.any()
andPromise.all()
withArray.prototype.some()
andArray.prototype.every()
.- Promise.allSetteled([]): will wait for all input promises to complete, regardless of whether or not one rejects.
Fulfills when all promises settle. And Return
results
object with below datastatus
: A string, either "fulfilled" or "rejected", indicating the eventual state of the promise.value
: Only present if status is "fulfilled". The value that the promise was fulfilled with.reason
: Only present if status is "rejected". The reason that the promise was rejected with.- Promise.race([])
- Promise.all([]) : static method takes an
- GeneratorFunction
function* generator(i,end) { while (i<end){ yield i++; } } const range = generator(0,10); for(let step of range){ console.log(step); } // 0,1,2,3,....,9
- AsyncGeneratorFunction
- Generator
- AsyncGenerator
- AsyncFunction
- Reflection :
Mention some array method which are modified orginal array
and mention some method which are not modifying orginal array
Modifying Orginal Array
arr.pop()
remove from last index and returnremoved item
arr.push()
insert in last index and returnlength of modified array
arr.unshift()
insert in first index and returnlength of modified array
arr.shift()
remove from fisrt index and returnremoved item
arr.splice(fromIndex,length)
remove from index to length and returnnew array with removed values
arr.reverse()
reverse the original array and returnreversed array
Not modifying Orginal Array
[1,2,3].map(e=>e*2)
return new array [2,4,6][2,4,6].filter(e=>e>2
return new array [6][1,2,3,4,5].slice(startIndex,endIndex)
return new array with the new slice, endIndex is not include[1,2,3].concat([4,5])
merge the array with existing one and return new array
Create New Array
- Array.from :
const arr = Array.from({length:5},(_,index) => index+1) // [1,2,3,4,5]
- Array.prototype.fill:
arr.fill(0) // [0,0,0,0,0]
Numeric Conversion – Occurs in math operations. Can be performed with Number(value).
Value | Becomes |
---|---|
undefined |
NaN |
null |
0 |
true / false |
1 / 0 |
string |
The string is read “as is”, whitespaces (includes spaces, tabs \t, newlines \n etc.) from both sides are ignored. An empty string becomes 0. An error gives NaN. |
Boolean Conversion – Occurs in logical operations. Can be performed with Boolean(value).
Follows the rules:
Value | Becomes |
---|---|
0 , null , undefined , NaN , "" |
false |
any other value | true |
(index value)
Those object are working with for...of
are iterable. Iterable objects like arrays
, strings
, sets
, maps
, etc. Now if [Symbol.iterator]
implemented in object, it also work as iterable
let range = {
from: 1,
to: 5
};
// 1. call to for..of initially calls this
range[Symbol.iterator] = function() {
// ...it returns the iterator object:
// 2. Onward, for..of works only with the iterator object below, asking it for next values
return {
current: this.from,
last: this.to,
// 3. next() is called on each iteration by the for..of loop
next() {
// 4. it should return the value as an object {done:.., value :...}
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
};
// now it works!
for (let num of range) {
console.log(num); // 1, 2, 3, 4, 5
}
(key value)
Those object are working with for...in
are enumarable.
const person = {
name: 'John',
age: 30,
occupation: 'Developer'
};
for (const key in person) {
console.log(`${key}: ${person[key]}`);
}
JavaScript Hoisting refers to the process whereby the interpreter appears to move the declaration of functions, variables, classes, or imports to the top of their scope, prior to execution of the code.
It’s preferred to capitalize a constructor function.
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
var car1 = new Car('Chevy', 'Blazer', 2015);
var car2 = new Car('Ford', 'Taurus', 2018);
console.log('Car 1 is a ' + car1.year + ' ' + car1.make + ' ' + car1.model);
// Output: Car 1 is a 2015 Chevy Blazer
console.log('Car 2 is a ' + car2.year + ' ' + car2.make + ' ' + car2.model);
// Output: Car 2 is a 2018 Ford Taurus
In JavaScript, a pure function is a function that, given the same input, will always return the same output, and it has no side effects.
Here's a breakdown of those two key characteristics:
Deterministic: A pure function will always produce the same output given the same input. There's no randomness involved. No Side Effects: A pure function doesn't modify variables outside its scope, mutate its arguments, perform I/O operations (like reading from files or modifying DOM elements), or interact with the external world in any other way. Its only effect is to compute the return value. For example:
// Pure function
function add(a, b) {
return a + b;
}
// Impure function (has side effect)
let result = 0;
function addToResult(x) {
result += x;
}
// Impure function (returns different values for same input)
function getRandomNumber() {
return Math.random();
}
In JavaScript, a higher-order function is a function that takes another function as an argument or returns a function as its result. Higher-order functions are a fundamental concept in functional programming and enable powerful and flexible programming paradigms such as function composition
, currying
, and lazy evaluation
.
Function expressions are when you create a function and assign it to a variable. The function is anonymous, which means it doesn’t have a name.
function funcDeclaration() {
return 'A function declaration';
}
let funcExpression = function () {
return 'A function expression';
}
There are a few key differences between function expressions and function declarations:
- Function declarations are hoisted, while function expressions are not. This means that you can call a function declaration before it is defined, but you cannot do this with a function expression.
- With function expressions, you can use a function immediately after it is defined. With function declarations, you have to wait until the entire script has been parsed.
- Function expressions can be used as an argument to another function, but function declarations cannot.
- Function expressions can be anonymous, while function declarations cannot.
"Use strict" is like setting rules for your JavaScript code. It makes sure your code follows stricter guidelines, catching mistakes that could cause problems later on. It helps you write cleaner, safer code by enforcing better coding practices.
Without "use strict":
// This code will run without any warnings
x = 10; // No need to declare 'x' with var, let, or const
console.log(x); // Outputs 10
With "use strict":
"use strict";
// This code will show an error
x = 10; // Error: 'x' is not defined
console.log(x); // This line won't be executed due to the error above
Note: Javascript
ES6 Module
andClass
are built-in strict mode.
function expression that annonymouse and called immediately after its defined.
(function () {
// code in here
}());
and it's useful for maintainable module code with out side effecting as it is fall into a function scope with it's property and methods.
let myModule = (function () {
let privateMethod = function () {
console.log('A private method');
},
someMethod = function () {
console.log('A public method');
},
anotherMethod = function () {
console.log('Another public method');
};
return {
someMethod: someMethod,
anotherMethod: anotherMethod
};
}());
In JavaScript, a closure is a combination of a function and the lexical environment within which that function was declared. This lexical environment consists of any variables that were in scope at the time the closure was created. Example
function queryBuilder() {
let query = '';
return function(statement) {
// query variable is in its parent scope or outer scope or in lexical scope
// it accessable even if outer function is executed
query+=statement;
if(statement.indexOf(';') > -1) {
let re = query;
query='';
return re;
}
return 'building....';
}
}
const query = queryBuilder();
console.log(query('select'));
console.log(query(' * '));
console.log(query(' from '));
console.log(query(' user where id=1'));
console.log(query(' limit 1;')); // output 'select * from user where id=1 limit 1;'
Currying is a functional programming technique in JavaScript where a function with multiple arguments is transformed into a sequence of nested functions, each taking a single argument. The curried function returns a new function for each argument until all arguments have been supplied, at which point it executes and returns the result.
As Usual Implementation
const totalPrice = (price,taxAmount) => price+(price*taxAmount);
console.log(totalPrice(30,0.15)); // output 34.5
console.log(totalPrice(100,0.15)); // output 115
Currying Implementation
const tax = (taxAmount) => (price) => price+(price*taxAmount);
const totalPrice= tax(0.15);
console.log(totalPrice(30)); // output 34.5
console.log(totalPrice(100)); // output 115
Function composition is a fundamental concept in functional programming where two or more functions are combined to produce a new function. The output of one function becomes the input of another, allowing you to create complex behavior by chaining together simpler functions.
Example
const split = str => str.split('');
const reverse = arr => arr.reverse();
const join = arr => arr.join('');
const compose = (...functions) => (str) => functions.reduce((acc,fn) => fn(acc),str);
// reverse a string
const composedFunction= compose(split,reverse,join);
console.log(composedFunction('hello')) // output 'olleh'
Lazy evaluation is a strategy where an expression is not evaluated until its value is actually needed. In JavaScript, this can be achieved using higher-order functions or by using generator functions. This technique can help improve performance and optimize memory usage in scenarios where computations are resource-intensive or when dealing with potentially infinite data sets.
Explaination
Suppose your script compute only array of size two, but given a large array dataset. How do you handle this situation, simple answer is by using Lazy Evalution
strategy.
function makeSmallDataSet(longDataSet) {
const chunks = [];
for (let i = 0; i < longDataSet.length; i += 2) {
const chunk = longDataSet.slice(i, i + 2);
chunks.push(chunk);
}
return chunks;
}
// Example long array
const longArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
// Split the long array into 2x2 arrays
const intermediateDataSet = makeSmallDataSet(longArray);
console.log(intermediateDataSet); // [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ], [ 9, 10 ], [ 11, 12 ] ]
function lazyEvalution(data){
const chunks = makeSmallDataSet(data);
const cpuIntesiveTask= function (stream){
// now process two size array with cpu intensive function
}
for(let chunk of chunks){
cpuIntesiveTask(chunk);
}
}
In JavaScript, a pipeline is a sequence of functions where the output of one function becomes the input of the next. It's a common pattern used for data transformation and processing, allowing you to compose complex operations by chaining together simpler functions.
Example
const split = str => str.split('');
const reverse = arr => arr.reverse();
const join = arr => arr.join('');
const makePipeline = (...functions) => (str) => functions.reduce((acc,fn) => fn(acc),str);
const startPiping= makePipeline(split,reverse,join,split);
console.log(startPiping('hello')); // output [ 'o', 'l', 'l', 'e', 'h' ]
with Object.freeze()
method you can set any object to immutable.
const arr = [1, 2, 3, 4, 90];
Object.freeze(arr);
arr.pop(); // Throw TypeError
Only specific property to make immutable
const person={
name:'John',
age:30
}
Object.defineProperty(person,'name',{
value:'Jane',
writable:false
});
person.name='Jane'; // TypeError: Cannot assign to read only property 'name' of object
A way to implement an enum in JavaScript by creating an Object of key/value pairs and using the Object.freeze() function to make it immutable:
const directions = Object.freeze({
north: 0,
south: 1,
east: 2,
west: 3
});
Every data types in js are extended from Object
except null
const arr= [1,2,3];
console.log(arr.__proto__);
// it log all array functionality
console.log(arr.__proto__.__proto__);
// it log all object functionality
console.log(arr.__proto__.__proto__.__proto__);
// it log null and proto chaining is stop
If used postfix, with operator after operand (for example, x++), the increment operator increments and returns the value before incrementing.
If used prefix, with operator before operand (for example, ++x), the increment operator increments and returns the value after incrementing.
let x =3;
let y=++x; // prefix increment return incremented value
console.log(x,y,"x,y"); // 4,4
y=x++; // postfix increment return without incremented value
console.log(x,y,"x,y"); // 5,4
y=--x; // prefix increment return decremented value
console.log(x,y,"x,y"); // 4,4
y=x--; // postfix increment return without decremented value
console.log(x,y,"x,y"); // 3,4
You can this
configurable with these methods,
apply
with comma seperated params.
function originalFunction(param1,param2){
// as you see here is no reference for `name` variable
// when you call by "call", "apply", "bind"
// you pass a "object" which have a 'name' property
console.log(this.name);
return ;
}
const result = originalFunction.apply(thisArg, param1, param2, ...);
call
with params in array
const result = originalFunction.call(thisArg, [param1, param2, ...]);
bind
is currying implementation,it make invokable for later. You can call it later as many time as you need
const boundFunction = originalFunction.bind(thisArg, param1, param2, ...);
boundFunction();
pop
, push
, shift
, and splice
modify the original array.
console.log([1,2,3].pop()) // return the
Microtask Queue | Macrotask Queue |
---|---|
Resolve promise A | Read file (I/O operation) |
Execute process.nextTick callbacks | Timer (setTimeout, setInterval) |
Execute event emitter callbacks | Network request (HTTP) |