Skip to content

Instantly share code, notes, and snippets.

@gergoszka
Last active September 26, 2021 13:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gergoszka/6077fea872157d2f9425cb9391ad8e8d to your computer and use it in GitHub Desktop.
Save gergoszka/6077fea872157d2f9425cb9391ad8e8d to your computer and use it in GitHub Desktop.

How many data types are there in modern JS?

There are eight basic data types in JavaScript: string, number, bigint, boolean, undefined, null, symbol, object. Here, all data types except Object are primitive data types.

// What output will the following code produce?
console.log(typeof 1); // number
console.log(typeof ''); // string
console.log(typeof {}); // object
console.log(typeof (() => {})); // function
console.log(typeof function() {}); // function
console.log(typeof true); // boolean
console.log(typeof NaN); //number
console.log(typeof undefined); // undefined
console.log(typeof null); //object
console.log(typeof 12n); //bigint
console.log(typeof []); //object

Data types convesion

In some scenarios JS automatically converts one data type to another based on the situation. This is called implicit conversion. But we can also convert them explicitly using built-in methods, like Number() to convert the passed argument into a number when applicable.

// What output will the following code produce?
console.log('3' + 2); // 32
console.log('3' + true); // 3true
console.log('3' + undefined); // 3undefined
console.log('4' * 2;) // 8
console.log(3 - '2'; // 1
console.log(4 + true); //5
console.log('hello' - 'world'); //NaN

What is Symbol type used for?

Symbols are immutable and unique data types. Even if we create many symbols with the same description, they are different values. Symbols allow us to create “hidden” properties of an object, that no other part of code can accidentally access or overwrite.

Difference between value types and reference types

In JS primitive types are passed as values: meaning that each time a value is assigned, a copy of that value is created. On the other hand objects are references. If you modify the object, then all variables that reference that object are going to change.

// What output will the following code produce?
const x = {};

function foo(y) {
  y.a = 2;
};

foo(x);

console.log(x); // { a: 2 }

function bar(y) {
  y = {}
}

bar(x);

console.log(x); // { a: 2 }

const z = 23;

function baz(y) {
  y = 25;
}
baz(z);
console.log(z); // 23

Hoisting. How does the hoisting work?

Hoisting in JavaScript is a behavior in which a function or a variable can be used before declaration. While var is hoisted, let and const does not allow hoisting.

// What output will the following code produce?
x();

function x() {
  console.log(22); //22, because hoisting
}
// What output will the following code produce?
console.log(x); // [Function: x]
var x = 20;

function x() {
}
console.log(x); // 20
// What output will the following code produce?
var x = 2;

function y(x) {
  console.log(++x); //3
}

y(x);

console.log(x); // 2
// What output will the following code produce?
var x = 2;

function y() {
  console.log(++x); // 3
}

y();

console.log(x); // 3
// What output will the following code produce?
var x = 2;

function y() {
  x = 1;
  console.log(x); // 1
  {
    var x = 3;
  }
  console.log(x); // 3
}

y();

console.log(x); // 2
// Is this code erroneous. Why?
// It is, because arrow function cannot be hoisted.
x();
  
const x = () => {
  console.log(22);
}

Variable declaration. Difference between var, let, const?

Var is the old way of declaring variables, meanwhile let and const were introduced in ES6 and are the prefered way of declaring variables nowadays. Var is function scoped, allows hoisting and can be redeclared while let is block scoped, can't be hoisted and doesn't allow redeclaring. Const is almost the same as let, except it's value cant be changed after initialization.

// Is this code erroneous. Why?
// No, because var varaibles can be hoisted
x = 2;
var x;
// Is this code erroneous. Why?
// It is, because let varibles cannot be hoisted
x = 2;
let x;
// Is this code erroneous. Why?
// It is, because const cannot be re-assigned
const x = {};
x = 2;
// Is this code erroneous. Why?
// No, you can add or remove elements from const objects
const x = {};
x.someProp = 2;

Function context. How do you understand keyword this in JS?

When this is used alone or in a function body it refers to the global context which in browsers is the window object. When used in a constructor function or in a class it refers to the object inside which it was used. When this is used inside an object's method, this refers to the object it lies within. Arrow functions do not have their own this. Also, when used inside an arrow function, this refers to its parent scope object. Lastly when this is used in a function with strict mode it will be undefined.

Difference between ordinary and arrow function

Arrow functions allow you to create functions in a cleaner way compared to regular functions, but they have several important differences too. They don't have their own this, so whenever we call this inside an arrow function it will refer to it's parent scope. Also they don't have argument binding, so the the argument variable is inaccessable but if you need all the argument values you can use the spread operator.

Regular Functions Arrow Functions
this value - Simple invocation : undefined or global object
- Method invocation: object owning the method
- Indirect invocation: "myFunc.call(arg)" this will be the first argument
- Constructor Invocation: newly created instance
- Always the parent's this value
Constructors Can easily construct objects using the new keyword. Cannot make new object, because of the lexical use of this.
Arguments object Inside a regular function the arguments variable is an array-like object containing the invocation arguments No arguments keyword is defined inside an arrow function.
If you need access to the arguments of the arrow function, then you can use the rest parameters: const arrowFunc = (…args) =>{}
Implicit return If the return statement is missing, or there’s no expression after return statement, the regular function implicitly returns undefined. If the arrow function contains one expression, and you omit the function’s curly braces, then the expression is implicitly returned.

Methods to modify function context

Call: The call() method calls a function with a given this value and arguments provided individually.
Apply: The apply() method calls a function with a given this value, and arguments provided as an array.
Bind: The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

// What output will the following code produce?
const obj = {
    name: 'John',
    sayHi() {
      console.log('Hi!, I am ' + this.name);
    },
    sayHiArrow: () => {
      console.log('Hi!, I am ' + this.name);
    },
    anotherObj: {
      name: 'Pete',
      sayHi() {
        console.log('Hi!, I am ' + this.name);
      }
    }
  }
  
  obj.sayHi();// Hi!, I am John
  obj.sayHiArrow();//Hi!, I am undefined
  obj.anotherObj.sayHi(); //Hi!, I am Pete
  const func = obj.sayHi;
  func();//Hi!, I am undefined
  func.apply(obj); //Hi!, I am John
  func.call(obj.anotherObj);//Hi!, I am Pete
  const func2 = obj.sayHi.bind(obj.anotherObj);
  func2();//Hi!, I am Pete

Scope and closures

A scope defines what variables or functions we have access to. There are two kinds of scope: global scope and local scope. And within the local scope we differentiate block and function scopes. A closure is when we create a function within another function, here the inner function is the closure. This closure is usually returned so we can use the outer function’s variables at a later time. They are mostly used to controll side effects and to create private variables.

// Write a calculator

const calculator = new makeCalc();
calculator.add(2);
calculator.print();
// prints 2
calculator.mul(-2);
calculator.print();
// prints -4
calculator.div(-2);
calculator.print();
// prints 2

function makeCalc() {
    this.result = 0,
    this.add = function (num) {
        this.result += num;
    }
    this.print = function () {
        console.log(this.result)
    }
    this.mul = function (num) {
        this.result *= num
    }
    this.div = function (num) {
        this.result /= num
    }
}

What is the difference between scope and context. During which time of program execution each one is created?

Scope is relevant in regards to the access of variables, while context is important when we want to know the value of this. Context is decided at runtime, while scopes are created when the code is compiled.

Asynchronous code. Methods that generate asynchronousity in browser, node.js

We sometimes have a piece of code (like a fetch request) where we are waiting for a response, but we don't know how long it will take, so this can't be solved synchronously. For this javascript has old-style callbacks and newer promise-style code. Async programing can also be achieved by setTimeout, setInterval, setImmediate and other functions.

What is async/await in a nutshell?

Async/await is a special syntax that works with promises in a more comfortable fashion. The async keyword can be placed in front of a function, this makes the function return a promise, which we can access with the promise.then() syntax or by using await. Await works only inside async functions and suspends the function execution until the promise is resolved.

Event loop. Stages of Event loop. Micro and macro tasks.

The event loop is javascript's way of exacuting asynchronous code, without the JS Engine being able to multithread. First the task is added to the Call Stack and executed. If its and async call it gets passed to the browser API which completes the task while the JS Engine keeps executing tasks. After the browser API is done it pushes the macrotasks to the Task queue and microtasks to the Job queue. The event loop prioritizes executing tasks from the job queue over the task queue. Also, it ries to process all queued microtasks between two macrotask.
Examples:
macrotasks: setTimeout, setInterval
microtasks: Promises, queueMicrotask

// Which output will this code produce?
// Why?

setTimeout(() => {
    console.log(1);
    Promise.resolve()
      .then(() => {
        console.log(2);
      })
      .then(() => {
        console.log(3);
      })
  }, 0)
  
  Promise.resolve().then(() => {
    console.log(4);
  });
  console.log(5);
  Promise.resolve().then(() => {
    console.log(6);
  });
  
  setTimeout(() => {
    console.log(7);
  }, 0)

  //5 4 6 1 2 3 7
  //Because 5 is a sync call and the event loop prioritizes Promises over setTimeouts
// Which output will this code produce?
// Why? How to make it work correctly?

for(var i = 0; i < 10; i++) { //let i = 0;
    setTimeout(() => {
      console.log(i);
    }, 0);
}

//Because the setTimeouts will be executed after the for loop is finished 
//and they share the same variable because of var all of them will be called with i = 10.
//With let there will be a distinct i for each iteration of the loop.
// Which output will this code produce?
// Why? 

Promise.reject()
  .then(() => console.log(1))//this wont run bc the promise is rejected
  .catch(() => console.log(2))//runs when a promise is rejected
  .then(() => console.log(3))//the above catch ran so this will also run
  .catch(() => console.log(4))//the above catch ran so this won't run
  .finally(() => console.log(5))//finally runs at the end wheter the promise is resolved or rejected 

// so the output is 2 3 5 

How does inheritance works in JS. Which two methods of inheritance implementation in JS do you know.

Regarding inheritence JavaScript only has one construct: objects. Each object has a private property which holds a link to another object called its prototype. That prototype object has a prototype of its own, and so on until an object is reached with null as its prototype. By definition, null has no prototype, and acts as the final link in this prototype chain. Nearly all objects in JavaScript are instances of Object which sits on the top of a prototype chain. Prototyping and class inheritence are two ways js handles inheritence.

// Write a class that does the following.
// don't use class syntax, you are allowed to use prototypes only
function Pet (type) {
    this.type = type,
    this.speed = 25
}
Pet.prototype.printHi = function (){ return `Hi, i am a ${this.type}. My speed is ${this.speed}`}

function Tiger (){
    this.type = 'tiger'
    this.speed = 30
}
Tiger.prototype = Object.create(Pet.prototype)


// Write it again using es6 class syntax
class Pet {
    constructor (type) {
        this.type = type,
        this.speed = 25
    }

    printHi(){
        return `Hi, i am a ${this.type}. My speed is ${this.speed}`
    }
}

class Tiger extends Pet {
    constructor(){
        super('tiger'),
        this.speed = 30
    }
}

const pony = new Pet('pony');
console.log(pony.type); //pony
console.log(pony.speed); //25
console.log(pony.printHi()) // Hi, i am pony. My speed is 25

const tiger = new Tiger();
console.log(tiger.type); // tiger
console.log(tiger.speed); // 30
console.log(tiger.printHi()) // Hi, i am tiger. My speed is 30
// Write a sortNumbers method, on Array which will be available to use on any array, it'll sort numbers in ascending order.
// It always creates a new array instead of sorting in place
// You are not allowed to use Array.sort in this task. (clue: If you are stuck, you may want to read what bubble sort is)

Array.prototype.sortAscending = function() {
    let newArray = [...this];
    for (let i = 0; i < newArray.length; i++){
        for (let j = 0; j < newArray.length; j++){
            if (newArray[j] > newArray[j+1]){
                let tmp = newArray[j];
                newArray[j] = newArray[j+1];
                newArray[j+1] = tmp;
            }
        }
    }
    return newArray;
}

const arr = [3, 2, 6, 5];
const sortedArray = arr.sortAscending();
console.log(arr)//[3, 2, 6, 5]
console.log(sortedArray)//[2, 3, 5, 6]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment