70 Javascript Interview Questions

Good day, friends!

I hope this article will be useful to both novice developers and experienced ones.

In questions which seemed to me more difficult than others, references to additional literature are given.

I would be grateful for the detailed comments. All comments will be taken into account when editing the article.

So let's go.

70 Javascript Interview Questions


Questions:
1. What is the difference between null and undefined?
2. What is the && operator used for?
3. What is the "||" operator used for?
4. Is using the unary plus (+ operator) the fastest way to convert a string to a number?
5. What is a DOM?
6. What is Event Propogation?
7. What is Event Bubbling?
8. What is Event Capturing?
9. What is the difference between the event.preventDefault () and event.stopPropagation () methods?
10. How to learn about using the event.preventDefault () method?
11. Why does obj.someprop.x lead to an error?
12. What is an event target or target element (event.target)?
13. (event.currentTarget)?
14. "==" "==="?
15. false?
16. "!!"?
17. ?
18. (Hoisting)?
19. (Scope)?
20. (Closures)?
21. JS ?
22. , ?
23. «use strict»?
24. this?
25. ?
26. IIFE?
27. Function.prototype.apply?
28. Function.prototype.call?
29. call apply?
30. Function.prototype.bind?
31. JS ?
32. (Higher Order Functions)?
33. JS (First-class Objects)?
34. Array.prototype.map?
35. Array.prototype.filter?
36. Array.prototype.reduce?
37. arguments?
38. , ?
39. b ?
40. ECMAScript?
41. JS ES6 ECMAScript2015?
42. «var», «let» «const»?
43. (Arrow Functions)?
44. (Classes)?
45. (Template Literals)?
46. (Object Destructuring)?
47. (Modules)?
48. Set?
49. (Callback Function)?
50. (Promises)?
51. async/await?
52. spread- rest-?
53. (Default Parameters)?
54. (Wrapper Objects)?
55. (Implicit and Explicit Coercion)?
56. NaN? , NaN?
57. , ?
58. , , ( "%")?
59. ?
60. AJAX?
61. JS ?
62. Object.freeze Object.seal?
63. «in» hasOwnProperty?
64. What techniques of working with asynchronous code in JS do you know?
65. What is the difference between a normal function and a functional expression?
66. How to call a function in JS?
67. What is memorization or memoization?
68. How would you implement the auxiliary function of memorization?
69. Why typeof null returns object? How to check if a value is null?
70. What is the “new” keyword used for?

1. What is the difference between null and undefined?


To begin, let's talk about what they have in common.

Firstly, they belong to 7 JS "primitives" (primitive types):

let primitiveTypes = ['string', 'number', 'null', 'undefined', 'boolean', 'symbol', 'bigint']

Secondly, they are false values, i.e. the result of converting them to a boolean using Boolean () or the operator "!!" is false:

console.log(!!null) // false
console.log(!!undefined) // false

console.log(Boolean(null)) // false
console.log(Boolean(undefined)) // false

Okay, now about the differences.

undefined is the default value:
  • a variable to which no value has been assigned, i.e. a declared but not initialized variable;
  • a function that does not return anything explicitly, for example, console.log (1);
  • nonexistent property of the object.

In these cases, the JS engine sets the value to undefined.

let _thisIsUndefined
const doNothing = () => {}
const someObj = {
    a: 'ay',
    b: 'bee',
    c: 'si'
}
console.log(_thisIsUndefined) // undefined
console.log(doNothing()) // undefined
console.log(someObj['d']) // undefined

null is the "value of no value". null is the value that is assigned to the variable explicitly. In the example below, we get null when the fs.readFile method works without errors:

fs.readFile('path/to/file', (e, data) => {
    console.log(e) //    null
if(e) {
    console.log(e)
}
    console.log(data)
})

When comparing null and undefined, we get true when using the "==" operator, and false when using the "===" operator. About why this happens, see below.

console.log(null == undefined) // true
console.log(null === undefined) // false

2. What is the && operator used for?


The && operator (logical and) finds and returns the first false value or the last operand when all values ​​are true. It uses a short circuit to avoid unnecessary costs:

console.log(false && 1 && []) // false
console.log(' ' && true && 5) // 5

With the if statement:

const router: Router = Router()

router.get('/endpoint', (req: Request, res: Response) => {
    let conMobile: PoolConnection
    try {
        //    
    } catch (e) {
        if (conMobile) {
            conMobile.release()
        }
    }
})

Same thing with the && operator:

const router: Router = Router()

router.get('/endpoint', (req: Request, res: Response) => {
    let conMobile: PoolConnection
    try {
        //    
    } catch (e) {
        conMobile && conMobile.release()
    }
})

3. What is the "||" operator used for?


The operator "||" (boolean or) finds and returns the first true value. It also uses a short circuit. This operator was used to assign default parameters in functions before the default parameters were standardized in ES6.

console.log(null || 1 || undefined) // 1

function logName(name) {
    let n = name || Mark
    console.log(n)
}

logName() // Mark

4. Is using the unary plus (+ operator) the fastest way to convert a string to a number?


According to MDN , the + operator is indeed the fastest way to convert a string to a number, since it does not perform any operations on a value that is a number.

5. What is a DOM?


The DOM or Document Object Model is an application programming interface (API) for working with HTML and XML documents. When the browser first reads (“parses”) the HTML document, it forms a large object, a really large object based on the document - the DOM. The DOM is a tree structure (document tree). The DOM is used to interact and change the structure of the DOM itself or its individual elements and nodes.

Let's say we have this HTML:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document Object Model</title>
</head>

<body>
    <div>
        <p>
            <span></span>
        </p>
        <label></label>
        <input>
    </div>
</body>

</html>

The DOM of this HTML looks like this:



In JS, the DOM is represented by a Document object. The Document object has a large number of methods for working with elements, their creation, modification, deletion, etc.

6. What is Event Propagation?


When an event occurs in a DOM element, it actually occurs not only in it. The event "propagates" from the Window object to the element that called it (event.target). In this case, the event sequentially permeates (affects) all the ancestors of the target element. An event propagation has three stages or phases:
  1. Immersion (capture, interception) phase - an event occurs in the Window object and descends to the event target through all its ancestors.
  2. The target phase is when the event reaches the target element.
  3. Ascending phase - an event rises from event.target, sequentially passes through all its ancestors and reaches the Window object.



Read more about the distribution of events here and here .

7. What is an event popup?


When an event occurs in a DOM element, it affects not only this element. An event “pops up” (like an air bubble in water), passes from the element that caused the event (event.target) to its parent, then rises even higher, to the parent of the element’s parent, until it reaches the Window object.

Let's say we have this markup:

<div class="grandparent">
    <div class="parent">
        <div class="child">1</div>
    </div>
</div>

And such a JS:

function addEvent(el, event, callback, isCapture = false) {
    if (!el || !event || !callback || typeof callback !== 'function') return

    if (typeof el === 'string') {
        el = document.querySelector(el)
    }
    el.addEventListener(event, callback, isCapture)
}

addEvent(document, 'DOMContentLoaded', () => {
    const child = document.querySelector('.child')
    const parent = document.querySelector('.parent')
    const grandparent = document.querySelector('.grandparent')

    addEvent(child, 'click', function(e) {
        console.log('child')
    })

    addEvent(parent, 'click', function(e) {
        console.log('parent')
    })

    addEvent(grandparent, 'click', function(e) {
        console.log('grandparent')
    })

    addEvent('html', 'click', function(e) {
        console.log('html')
    })

    addEvent(document, 'click', function(e) {
        console.log('document')
    })

    addEvent(window, 'click', function(e) {
        console.log('window')
    })
})

The addEventListener method has a third optional parameter - useCapture. When its value is false (the default), the event begins with the ascent phase. When its value is true, the event begins with the immersion phase (for the "listeners" of events attached to the target of the event, the event is in the target phase, and not in the dive or ascent phases. Events in the target phase are triggered by all listeners on the element in the in which they were registered regardless of the useCapture parameter - approx. If we click on the child element, the console will display: child, parent, grandparent, html, document, window. Here's what an event popup is.

8. What is an immersion event?


When an event occurs in a DOM element, it occurs not only in it. In the immersion phase, the event descends from the Window object to the event target through all its ancestors.

Markup:

<div class="grandparent">
    <div class="parent">
        <div class="child">1</div>
    </div>
</div>

JS:

function addEvent(el, event, callback, isCapture = false) {
    if (!el || !event || !callback || typeof callback !== 'function') return

    if (typeof el === 'string') {
        el = document.querySelector(el);
    }
    el.addEventListener(event, callback, isCapture)
}

addEvent(document, 'DOMContentLoaded', () => {
    const child = document.querySelector('.child')
    const parent = document.querySelector('.parent')
    const grandparent = document.querySelector('.grandparent')

    addEvent(child, 'click', function(e) {
        console.log('child');
    }, true)

    addEvent(parent, 'click', function(e) {
        console.log('parent')
    }, true)

    addEvent(grandparent, 'click', function(e) {
        console.log('grandparent')
    }, true)

    addEvent('html', 'click', function(e) {
        console.log('html')
    }, true)

    addEvent(document, 'click', function(e) {
        console.log('document')
    }, true)

    addEvent(window, 'click', function(e) {
        console.log('window')
    }, true)
})

The addEventListener method has a third optional parameter - useCapture. When its value is false (the default), the event begins with the ascent phase. When its value is true, the event begins with the dive phase. If we click on the child element, we will see the following in the console: window, document, html, grandparent, parent, child. This is the immersion of the event.

9. What is the difference between the event.preventDefault () and event.stopPropagation () methods?


The event.preventDefault () method disables the default behavior of an element. If you use this method in the form element, it will prevent the form from submitting. If you use it in contextmenu, the context menu will be disabled (this method is often used in keydown to redefine the keyboard, for example, when creating a music / video player or text editor - approx. The event.stopPropagation () method disables the event propagation (its ascent or immersion).

10. How to learn about using the event.preventDefault () method?


To do this, we can use the event.defaulPrevented property, which returns a Boolean value that serves as an indicator of application to the element of the event.preventDefault method.

11. Why does obj.someprop.x lead to an error?



const obj = {}
console.log(obj.someprop.x)

The answer is obvious: we are trying to access the x property of someprop property, which is undefined. obj .__ proto __.__ proto = null, so undefined is returned, and undefined does not have the x property.

12. What is an event target or target element (event.target)?


In simple words, event.target is the element in which the event occurs, or the element that raised the event.

We have the following markup:

<div onclick="clickFunc(event)" style="text-align: center; margin: 15px;
border: 1px solid red; border-radius: 3px;">
    <div style="margin: 25px; border: 1px solid royalblue; border-radius: 3px;">
        <div style="margin: 25px; border: 1px solid skyblue; border-radius: 3px;">
            <button style="margin: 10px">
                Button
            </button>
        </div>
    </div>
</div>

And such a simple JS:

function clickFunc(event) {
    console.log(event.target)
}

We attached a “listener” to the outer div. However, if we click on the button, we get the layout of this button in the console. This allows us to conclude that the element that caused the event is the button itself, and not the external or internal divs.

13. What is the current purpose of the event (event.currentTarget)?


Event.currentTarget is the element to which the event listener is attached.

Similar markup:

<div onclick="clickFunc(event)" style="text-align: center;margin:15px;
border:1px solid red;border-radius:3px;">
    <div style="margin: 25px; border:1px solid royalblue;border-radius:3px;">
        <div style="margin:25px;border:1px solid skyblue;border-radius:3px;">
            <button style="margin:10px">
                Button
            </button>
        </div>
    </div>
</div>

And a slightly modified JS:

function clickFunc(event) {
    console.log(event.currentTarget)
}

We attached the listener to the outer div. Wherever we click, whether it be a button or one of the internal divs, in the console we always get the layout of the external div. This allows us to conclude that event.currentTarget is the element to which the event listener is attached.

14. What is the difference between the operators "==" and "==="?


The difference between the operator == (abstract or non-strict equality) and the operator === (strict equality) is that the first compares the values ​​after they are converted or cast to one type (Coersion), and the second - without such a conversion .

Let's dig deeper. And first, let's talk about the transformation.

A conversion is a process of casting a value to another type, or rather, a process of casting the compared values ​​to one type. When comparing, the operator "==" produces the so-called implicit comparison. The operator "==" performs some operations before comparing two values.

Suppose we compare x and y.

The algorithm is as follows:

  1. If x and y are of the same type, the comparison is performed using the "===" operator.
  2. x = null y = undefined true.
  3. x = undefined y = null true.
  4. x = , y = , x == toNumber(y) ( y ).
  5. x = , y = , toNumber(x) == y ( x ).
  6. x = , toNumber(x) == y.
  7. y = , x == toNumber(y).
  8. x = , , y = , x == toPrimitive(y) ( y ).
  9. x = , y = , , toPrimitive(x) == y.
  10. false.

Remember: to cast an object to a "primitive", the toPrimitive method first uses the valueOf method, then the toString method.

Examples:



All examples return true.

The first example is the first condition of the algorithm.
The second example is the fourth condition.
The third is the second.
The fourth is the seventh.
Fifth - eighth.
And the last is the tenth.



If we use the "===" operator, all examples except the first will return false, since the values ​​in these examples are of different types.

15. Why is the result of comparing two similar objects false?


let a = {
    a: 1
}
let b = {
    a: 1
}
let c = a

console.log(a === b) // false
console.log(a === c) // true ...

In JS, objects and primitives are compared differently. Primitives are compared by value. Objects - by reference or address in memory where the variable is stored. This is why the first console.log returns false and the second returns true. Variables “a” and “c” refer to the same object, while variables “a” and “b” refer to different objects with the same properties and values.

16. What is the operator "!!" used for?


The operator "!!" (double negation) leads the value to its right to a logical value.

console.log(!!null) // false
console.log(!!undefined) // false
console.log(!!'') // false
console.log(!!0) // false
console.log(!!NaN) // false
console.log(!!' ') // true
console.log(!!{}) // true
console.log(!![]) // true
console.log(!!1) // true
console.log(!![].length) // false

17. How to write multiple expressions on one line?


For this we can use the operator "," (comma). This operator "moves" from left to right and returns the value of the last expression or operand.

let x = 5

x = (x++, x = addFive(x), x *= 2, x -= 5, x += 10)

function addFive(num) {
    return num + 5
}

If we print the value of x to the console, we get 27. First, we increase the value of x by one (x = 6). Then we call the addFive () function with parameter 6, to which we add 5 (x = 11). After that, we multiply the value of x by 2 (x = 22). Then subtract 5 (x = 17). And finally, add 10 (x = 27).

18. What is hoisting?


Lift is a term that describes the rise of a variable or function in a global or functional scope.

In order to understand what Hoisting is, you need to understand what the execution context is.

The execution context is the environment in which the code is executed. The execution context has two phases - compilation and execution itself.

Compilation. In this phase, functional expressions and variables declared using the “var” keyword with the value undefined rise to the very top of the global (or functional) scope (as if moving to the beginning of our code. This explains why we can call functions before they announcements - approx.

Performance. In this phase, variables are assigned values, and functions (or methods of objects) are called or executed.

Remember: only functional expressions and variables declared using the “var” keyword are raised. Ordinary functions and arrow functions, as well as variables declared using the keywords “let” and “const”, are not raised.

Suppose we have code like this:

console.log(y)
y = 1
console.log(y)
console.log(greet('Mark'))

function greet(name) {
    return 'Hello ' + name + '!'
}

var y

We get undefined, 1 and 'Hello Mark!'.

Here's what the compilation phase looks like:

function greet(name) {
    return 'Hello ' + name + '!'
}

var y //  undefined

//    

//    
/*
console.log(y)
y = 1
console.log(y)
console.log(greet('Mark'))
*/

After the compilation phase is completed, the execution phase begins when the variables are assigned values ​​and functions are called.

More about Hoisting can be found here .

19. What is a scope?


A scope is a place where (or from where) we have access to variables or functions. JS we have three types of scopes: global, functional and block (ES6).

Global scope - variables and functions declared in the global namespace have a global scope and are accessible from anywhere in the code.

//   
var g = 'global'

function globalFunc() {
    function innerFunc() {
        console.log(g) //     g,    
    }
    innerFunc()
}

Functional scope (scope of a function) - variables, functions and parameters declared inside a function are available only inside this function.

function myFavouriteFunc(a) {
    if (true) {
        var b = 'Hello ' + a
    }
    return b
}
myFavouriteFunc('World')

console.log(a) // Uncaught ReferenceError: a is not defined
console.log(b) //  

Block scope - variables (declared using the keywords "let" and "const") inside the block ({}) are available only inside it.

function testBlock() {
    if (true) {
        let z = 5
    }
    return z
}

testBlock() // Uncaught ReferenceError: z is not defined

A scope is also a set of rules by which a variable is searched. If the variable does not exist in the current scope, its search is performed higher in the external visibility of the current scope. If there is no variable in the external scope, its search continues up to the global scope. If a variable is found in the global scope, the search stops; if not, an exception is thrown. The search is carried out by the closest to the current visibility areas and stops with finding the variable. This is called the Scope Chain.

//   
//    ->    ->   

//   
var variable1 = 'Comrades'
var variable2 = 'Sayonara'

function outer() {
    //   
    var variable1 = 'World'

    function inner() {
        //   
        var variable2 = 'Hello'
        console.log(variable2 + ' ' + variable1)
    }
    inner()
}
outer()
//    'Hello World',
//   variable2 = 'Hello'  variable1 = 'World'  
//     



20. What is a closure (Closures)?


This is probably the most difficult question from the list. I will try to explain how I understand closure.

In fact, closure is the ability of a function to create links to variables and parameters that are in the current scope, in the scope of the parent function, in the scope of the parent of the parent function, and so on to the global scope using the chain of scopes at creation time. Typically, scope is determined when a function is created.

Examples are a great way to explain closure:

//   
var globalVar = 'abc'

function a() {
    //   
    console.log(globalVar)
}

a() // 'abc'
//   
//    a ->   

In this example, when we declare a function, the global scope is part of the closure.



The “globalVar” variable does not matter in the picture, because its value may change depending on where and when the function will be called. But in the example above, globalVar will have the value “abc”.

Now the example is more complicated:

var globalVar = 'global'
var outerVar = 'outer'

function outerFunc(outerParam) {
    function innerFunc(innerParam) {
        console.log(globalVar, outerParam, innerParam)
    }
    return innerFunc
}

const x = outerFunc(outerVar)
outerVar = 'outer-2'
globalVar = 'guess'
x('inner')



The result is “guess outer inner”. The explanation is this: when we call the outerFunc function and assign the variable "x" the value returned by the innerFunc function, the parameter "outerParam" is equal to "outer". Despite the fact that we assigned the variable “outerVar” to “outer-2”, this happened after calling the outerFunc function, which “managed” to find the value of the variable “outerVar” in the scope chain, this value was “outer”. When we call "x" that refers to innerFunc, the value of "innerParam" is "inner" because we pass this value as a parameter when calling "x". globalVar has a value of “guess” because we assigned it that value before calling “x”.

An example of a misunderstanding of a circuit.

const arrFunc = []
for (var i = 0; i < 5; i++) {
    arrFunc.push(function() {
        return i
    })
}
console.log(i) // 5

for (let i = 0; i < arrFunc.length; i++) {
    console.log(arrFunc[i]()) //  5
}

This code does not work as expected. Declaring a variable using the var keyword makes this variable global. After adding functions to the arrFunc array, the value of the global variable “i” becomes “5”. Therefore, when we call the function, it returns the value of the global variable “i”. A closure stores a reference to a variable, not its value at creation time. This problem can be solved by using IIFE or by declaring a variable using the “let” keyword.

Read more about the closure here and here .

21. What values ​​in JS are false?


const falsyValues = ['', 0, null, undefined, NaN, false]

False are values ​​whose conversion to a boolean value is false.

22. How to check if a value is false?


Use the Boolean function or the operator "!!" (twice no).

23. What is the use strict directive used for?


“Use strict” is an ES5 directive that forces all of our code or the code of an individual function to execute in strict mode. Strict mode introduces some restrictions on writing code, thereby avoiding errors in the early stages.

Here are the limitations of strict mode.

You cannot assign values ​​or access undeclared variables:

function returnY() {
    'use strict'
    y = 123
    return y
}
returnY() // Uncaught ReferenceError: y is not defined

It is forbidden to assign global values ​​to read-only or write-only variables:

'use strict'
var NaN = NaN // Uncaught TypeError: Cannot assign to read only property 'NaN' of object '#<Window>'
var undefined = undefined
var Infinity = 'and beyond'

You cannot delete the “undeletable” property of an object:

'use strict'
const obj = {}

Object.defineProperties(obj, 'x', {
    value: 1
})

delete obj.x // Uncaught TypeError: Property description must be an object: x

Duplication of parameters is prohibited:

'use strict'

function someFunc(a, b, b, c) {} // Uncaught SyntaxError: Duplicate parameter name not allowed in this context

You cannot create functions using the eval function:

'use strict'

eval('var x = 1')

console.log(x) // Uncaught ReferenceError: x is not defined

The default value for this is undefined:

'use strict'

function showMeThis() {
    return this
}

showMeThis() // undefined

… etc.

24. What does this mean?


This usually refers to the value of the object that is currently executing or calling the function. “Right now” means that the value of this varies depending on the execution context, where we use this.

const carDetails = {
    name: 'Ford Mustang',
    yearBought: 2005,
    getName() {
        return this.name
    }
    isRegistered: true
}

console.log(carDetails.getName()) // Ford Mustang

In this case, the getName method returns this.name, and this refers to carDetails, the object in which getName is run, which is its "owner".

Add three lines after console.log:

var name = 'Ford Ranger'
var getCarName = carDetails.getName

console.log(getCarName()) // Ford Ranger

The second console.log produces a Ford Ranger, and this is weird. The reason for this behavior is that the "owner" of getCarName is the window object. Variables declared with the var keyword in the global scope are written to the properties of the window object. this in the global scope refers to the window object (unless it is a strict mode).

console.log(getCarName === window.getCarName) // true
console.log(getCarName === this.getCarName) // true

In this example, this and window refer to the same object.

One way to solve this problem is to use the call or apply methods:

console.log(getCarName.apply(carDetails)) // Ford Mustang
console.log(getCarName.call(carDetails)) // Ford Mustang

Call and apply take as the first argument an object that will be the value of this inside the function.

In IIFE, functions that are created in the global scope, anonymous functions, and internal functions of an object's methods, the default value for this is the window object.

(function() {
    console.log(this)
})() // window

function iHateThis() {
    console.log(this)
}
iHateThis() // window

const myFavouriteObj = {
    guessThis() {
        function getName() {
            console.log(this.name)
        }
        getName()
    },
    name: 'Marko Polo',
    thisIsAnnoying(callback) {
        callback()
    }
}

myFavouriteObj.guessThis() // window
myFavouriteObj.thisIsAnnoying(function() {
    console.log(this) // window
})

There are two ways to get Marko Polo.

First, we can store the value of this in a variable:

const myFavoriteObj = {
    guessThis() {
        const self = this //   this   self
        function getName() {
            console.log(self.name)
        }
        getName()
    },
    name: 'Marko Polo',
    thisIsAnnoying(callback) {
        callback()
    }
}

Secondly, we can use the arrow function:

const myFavoriteObj = {
    guessThis() {
        const getName = () => {
            //   this   
            console.log(this.name)
        }
        getName()
    },
    name: 'Marko Polo',
    thisIsAnnoying(callback) {
        callback()
    }
}

Arrow functions do not have this eigenvalue. They copy the meaning of this from the external lexical environment.

25. What is a prototype of an object?


In a nutshell, a prototype is a plan (diagram or project) of an object. It is used as a fallback for the properties and methods existing in this object. It is also one of the ways to exchange properties and functionality between objects. This is the basic concept of prototype inheritance in JS.

const o = {}
console.log(o.toString()) // [object Object]

Although the “o” object does not have the toString property, accessing this property does not cause an error. If a specific property is not in the object, its search is carried out first in the prototype of the object, then in the prototype of the prototype of the object, and so on until the property is found. This is called the prototype chain. At the top of the prototype chain is Object.prototype.

console.log(o.toString === Object.prototype.toString) // true

Read more about prototypes and inheritance here and here .

26. What is IIFE?


IIFE or Immediately Invoked Function Expression is a function that is called or executed immediately after creation or declaration. To create IIFE, you need to wrap the function in parentheses (the grouping operator), turning it into an expression, and then call it using another parentheses. It looks like this: (function () {}) ().

(function( ) { }( ))

(function( ) { })( )

(function named(params) { })( )

(( ) => { })

(function(global) { })(window)

const utility = (function( ) {
    return {
        // 
    }
})

All of these examples are valid. The penultimate example shows that we can pass parameters to IIFE. The last example shows that we can store the result of IIFE in a variable.

The best use of IIFE is to perform initialization configuration functions and prevent name conflicts with other variables in the global scope (pollution of the global namespace). We give an example.

<script src="https://cdnurl.com/somelibrary.js"></script>

We have a link to somelibrary.js library that provides some global functions that we can use in our code, but there are two methods in this library, createGraph and drawGraph, which we do not use because they contain errors. And we want to implement these functions on our own.

One way to solve this problem is to change the structure of our scripts:

<script src="https://cdnurl.com/somelibrary.js"></script>
<script>
    function createGraph() {
        // 
    }

    function drawGraph() {
        // 
    }
</script>

Thus, we redefine the methods provided by the library.

The second way is changing the names of our functions:

<script src="https://cdnurl.com/somelibrary.js"></script>
<script>
    function myCreateGraph() {
        // 
    }

    function myDrawGraph() {
        // 
    }
</script>

The third way is to use IIFE:

<script>
    const graphUtility = (function() {
        function createGraph() {
            // 
        }

        function drawGraph() {
            // 
        }
        return {
            createGraph,
            drawGraph
        }
    })
</script>

In this example, we create a utility variable that contains the IIFE result, which returns an object containing the createGraph and drawGraph methods.

Here is another problem that can be solved with IIFE:

val li = document.querySelectorAll('.list-group > li')
for (var i - 0, len = li.length; i < len; i++) {
    li[i].addEventListener('click', function(e) {
        console.log(i)
    })
}

Suppose we have an ul element with a list-group class containing 5 child elements li. And we want to display the value “i” in the console when clicking on a separate “li”. However, instead, the console always displays 5. The fault is all the fault.

One solution is IIFE:

var li = document.querySelectorAll('.list-group > li')
for (var i = 0, len = li.length; i < len; i++) {
    (function(currentIndex) {
        li[currentIndex].addEventListener('click', function(e) {
            console.log(currentIndex)
        })
    })(i)
}

The reason this code works as intended is because IIFE creates a new scope at each iteration, and we write the value “i” in currentIndex.

27. What is the Function.prototype.apply method used for?


Apply is used to bind a specific object to the this value of the called function.

const details = {
    message: 'Hello World!'
}

function getMessage() {
    return this.message
}

getMessage.apply(details) // Hello World!

This method is similar to Function.prototype.call. The only difference is that in apply, the arguments are passed as an array.

const person = {
    name: 'Marko Polo'
}

function greeting(greetingMessage) {
    return `${greetingMessage} ${this.name}`
}

greeting.apply(person, ['Hello']) // Hello Marko Polo

28. What is the function.prototype.call method used for?


Call is used to bind a specific object to the value of this function being called.

const details = {
    message: 'Hello World!'
};

function getMessage() {
    return this.message;
}

getMessage.call(details); // Hello World!

This method is similar to Function.prototype.apply. The difference is that in call arguments are passed separated by commas.

const person = {
    name: 'Marko Polo'
};

function greeting(greetingMessage) {
    return `${greetingMessage} ${this.name}`;
}

greeting.call(person, 'Hello'); // Hello Marko Polo

29. What is the difference between call and apply methods?


The difference between call and apply is how we pass arguments in the called function. In apply, the arguments are passed as an array, in call, separated by commas.

const obj1 = {
    result: 0
}

const obj2 = {
    result: 0
}

function reduceAdd() {
    let result = 0
    for (let i = 0, len = arguments.length; i < len; i++) {
        result += arguments[i]
    }
    this.result = result
}

reduceAdd.apply(obj1, [1, 2, 3, 4, 5]) // 15
reduceAdd.call(obj2, 1, 2, 3, 4, 5) // 15

30. What is the function.prototype.bind method used for?


Bind returns a new function whose this value is the object specified as the first parameter. Unlike bind, call and apply immediately call the function.

import React from 'react'

class MyComponent extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            value: ''
        }
        this.handleChange = this.handleChange.bind(this)
        //   handleChange   MyComponent
    }

    handleChange(e) {
        // 
    }

    render() {
        return ( < >
            <
            input type = {
                this.props.type
            }
            value = {
                this.state.value
            }
            onChange = {
                this.handleChange
            }
            /> </ >
        )
    }
}

31. What is functional programming and what features of JS allow us to talk about it as a functional programming language?


Functional programming is a declarative programming concept or pattern (pattern) of how applications are built, how functions containing expressions that calculate values ​​without changing the arguments that are passed to them are used.

The Array object contains the map, filter, and reduce methods, which are the most famous functions in the world of functional programming because of their usefulness and also because they do not modify the array, which makes these functions “clean”. JS also has a closure and higher-order functions that are characteristics of a functional programming language.

The map method returns a new array with callback results for each element of the array:

const words = ['Functional', 'Procedural', 'Object-Oriented']

const wordsLength = words.map(word => word.length)

The filter method creates a new array with all elements that satisfy the condition specified in the callback:

const data = {
    {
        name: 'Mark',
        isRegistered: true
    } {
        name: 'Mary',
        isRegistered: false
    } {
        name: 'Mae',
        isRegistered: true
    }
}

const registeredUsers = data.filter(user => user.isRegistered)

The reduce method performs a callback once for each element of the array, with the exception of voids, taking four arguments: the initial value (or the value from the previous callback), the value of the current element, the current index, and the iterated array:

const strs = ['I', ' ', 'am', ' ', 'Iron', ' ', 'Man']

const result = strs.reduce((acc, currentStr) => acc + str, '')

32. What are Higher Order Functions?


A higher-order function is a function that returns another function or accepts another function as an argument.

function higherOrderFunction(param, callback) {
    return callback(param)
}

33. Why are functions in JS called First-class Objects?


Functions are called first-class objects because they are processed just like any other value in JS. They can be assigned to variables, be a property of an object (method), an element of an array, an argument to another function, the value returned by the function. The only difference between a function and any other value in JS is that the function can be executed or called.

34. How would you implement the Array.prototype.map method?


function map(arr, mapCallback) {
    //   
    if (!Array.isArray(arr) || !arr.length || typeof mapCallback !== 'function') {
        return []
    } else {
        let result = []
        //         
        //       
        for (let i = 0, len = arr.length; i < len; i++) {
            result.push(mapCallback(arr[i], i, arr))
            //   mapCallback  result
        }
        return result
    }
}

The map method creates a new array with the result of calling the specified function for each element of the array.

35. How would you implement the Array.prototype.filter method?


function filter(arr, filterCallback) {
    //   
    if (!Array.isArray(arr) || !arr.length || typeof filterCallback !== 'function') {
        return []
    } else {
        let result = []
        // ...
        for (let i = 0, len = arr.length; i < len; i++) {
            //      
            if (filterCallback(arr[i], i, arr)) {
                //  ,  ,  result
                result.push(arr[i])
            }
        }
        return result
    }
}

The filter method creates a new array with all the elements that passed the test specified in the function being passed.

36. How would you implement the Array.prototype.reduce method?


function reduce(arr, reduceCallbak, initialValue) {
    // ..
    if (!Array.isArray(arr) || !arr.length || typeof filterCallback !== 'function') {
        return []
    } else {
        //        initialValue, 
        let hasInitialValue = initialValue !== undefined
        let value = hasInitialValue ? initialValue : arr[0]
        //      initialValue

        //    ,   1,       initialValue,   0,    
        for (let i = hasInitialValue ? 0 : 1, len = arr.length; i < len; i++) {
            //         reduceCallback 
            value = reduceCallback(value, arr[i], i, arr)
        }
        return value
    }
}

The reduce method applies the reducer function to each element of the array (from left to right), returning one resulting value.

37. What is an arguments object?


Arguments is a collection of arguments passed to a function. This is an array-like object, it has the length property, we can access a specific value using arguments [i], but it does not have the forEach, reduce, filter, and map methods. It allows you to find out the number of function parameters.

You can convert arguments to an array using Array.prototype.slice:

Array.prototype.slice.call(arguments)

Remember: in arrow functions, the arguments object does not work.

function one() {
    return arguments
}
const two = function() {
    return arguments
}
const three = function three({
    return arguments
})
const four = () => arguments

four() // arguments is not defined

Calling the four function results in a ReferenceError: arguments is not defined error. This problem can be solved using the rest statement:

const four = (...args) => args

This will automatically put all the parameters in an array.

38. How to create an object that does not have a prototype?


This can be done using Object.create:

const o1 = {}
console.log(o1.toString) // [object Object]

const o2 = Object.create(null) //      Object-create  -
//    -,   null
console.log(o2.toString) // o2.toString is not a function

39. Why in the presented code does the variable b become global when the function is called?



function myFunc(){
    let a = b = 0
}
myFunc()

This happens because the assignment operator ("=") has right-handed associativity, i.e. assigns values ​​from right to left. Therefore, the code takes the following form:

function myFunc(){
    let a = (b = 0)
}
myFunc()

First, the value 0 is assigned to the variable "b", which is not declared. The JS engine makes it global. The value (0) returned by b = 0 is then assigned to the local variable “a”.

This problem can be solved by first declaring local variables and then assigning values ​​to them:

function myFunc(){
    let a, b
    a = b = 0
}
myFunc()

40. What is ECMAScript?


ECMAScript is a specification, a standard scripting programming language, it is the basis of JS, so any changes to ECMAScript are reflected in JS.

The latest version of the ECMA-262 specification can be viewed here .

41. What new things did ES6 or ECMAScript2015 bring to JS?


  • Arrow Functions
  • Classes
  • Template Strings.
  • Enhanced Object literals
  • Destructuring (Object Destructuring).
  • Promises (Promises).
  • Generators
  • Modules
  • Symbol.
  • Proxies
  • Sets.
  • The default options.
  • Rest and spread operators.
  • Block scope (keywords “let” and “const”).

42. What is the difference between the keywords “var”, “let” and “const”?


Variables declared using the var keyword are global. This means that they are accessible from anywhere in the code:

function giveMeX(showX){
    if(showX){
        var x = 5
    }
    return x
}

console.log(giveMeX(false))
console.log(giveMeX(true))

The result of the first console.log will be undefined, the second - 5. We have access to the variable “x” because of its emergence into the global scope. The code from the example above is interpreted as follows:

function giveMeX(showX){
    var x //   undefined
    if(showX){
        x = 5
    }
    return x
}

The result of the first console.log is undefined, because declared variables that are not assigned a value are undefined by default.

Variables declared using the keywords "let" and "const" have a block scope. This means that they are only available inside the block ({}):

function giveMeX(showX){
    if(showX){
        let x = 5
    }
    return x
}

function giveMeY(showY){
    if(showY){
        let y = 5
    }
    return y
}

Calling these functions with the false parameter will result in a ReferenceError error, because the variables "x" and "y" are not accessible outside the block and their values ​​are not returned (do not pop up).

The difference between “let” and “const” is that in the first case we can change the value of the variable, and in the second - no (constant). At the same time, we can change the value of the property of an object declared using const, but not the property itself (variable).

43. What are arrow functions (Arrow Functions)?


Arrow function is a relatively new way to create functions in JS. Arrow functions are created faster and have more readable syntax than functional expressions. In arrow functions, the word "function" is omitted:

// ES5
var getCurrentDate = function(){
    return new Date()
}

// ES6
const getCurrentDate = () => new Date()

In a functional expression, we use the return keyword to return a value. In the arrow function, we do not do this, since arrow functions implicitly return values, provided that we return a single expression or value:

// ES5
function greet(name){
    return 'Hello ' + name + '!' 
}

// ES6
const greet = (name) => `Hello ${name}`
const greet2 = name = > `Hello ${name}`

We can also pass parameters to arrow functions. If we pass one parameter, we don’t have to wrap it in parentheses:

const getArgs = () => arguments

const getArgs2 = (...rest) => rest

Arrow functions do not have access to the arguments object. Therefore, calling the first function will result in an error. To get the parameters passed to the function, we can use the rest operator.

const data = {
    result: 0
    nums: [1,2,3,4,5]
    computeResult(){
        // this    data
        const addAll = () => {
        //     this   
        return this.nums.reduce((total, cur) => total + cur, 0)
        }
    this.result = addAll()
    }
}

44. What are classes?


Classes are a relatively new way of writing constructor functions in JS. This is syntactic sugar for constructor functions. Classes are based on the same prototypes and prototype inheritance:

// ES5
function Person(firstName, lastName, age, address){
    this.firstName = firstName
    this.lastName = lastName
    this.age = age
    this.address = address
}

Person.self = function(){
    return this
}

Person.prototype.toString = function(){
    return '[object Person]'
}

Person.prototype.getFullName = function(){
    return this.firstName + ' ' + this.lastName
}

// ES6
class Person{
    constructor(firstName, lastName, age, address){
        this.firstName = firstName
        this.lastName = lastName
        this.age = age
        this.address = address
    }

    static self(){
        return this
    }

    toString(){
        return '[object Person]'
    }

    getFullName(){
        return `${this.firstName} ${this.lastName}`
    }
}

Method overrides and inheritance from another class:

// ES5
Employee.prototype = Object.create(Person.prototype)

function Employee(firstName, lastName, age, address, jobTitle, yearStarted){
    Person.call(this, firstName, lastName, age, address)
    this.jobTitle = jobTitle
    this.yearStarted = yearStarted
}

Employee.prototype.describe = function(){
    return `I am ${this.getFullName()} and I have a position of #{this.jobTitle} and I started at ${this.yearStarted}}`
}

Employee.prototype.toString = function(){
    return '[object Employee]'
}

// ES6
class Employee extends Person{ //   Person
    constructor(firstName, lastName, age, address, jobTitle, yearStarted){
        super(firstName, lastName, age, address)
        this.jobTitle = jobTitle
        this.yearStarted = yearStarted
    }

    describe(){
       return `I am ${this.getFullName()} and I have a position of #{this.jobTitle} and I started at ${this.yearStarted}}` 
    }

    toString(){ //   toString  Person
        return '[object Employee]'
    }
}

How to learn about the use of prototypes?

class Something{ }

function AnotherSomething(){ }

const as = new AnotherSomething()
const s = new Something()

console.log(typeof Something) // function
console.log(typeof AnotherSomething) // function
console.log(as.toString()) // [object Object]
console.log(a.toString()) // [object Object]
console.log(as.toString === Object.prototype.toString)
console.log(a.toString === Object.prototype.toString)
//     true
// Object.prototype     
// Something  AnotherSomething   Object.prototype

45. What are Template Literals?


Template literals are a relatively new way to create strings in JS. Template literals are created using double backticks (``):

// ES5
var greet = 'Hi I\'m Mark'

// ES6
let greet = `Hi I'm Mark`

In template literals, we do not need to escape single quotes.
// ES5
var lastWords = '\n'
    + ' I \n'
    + ' am \n'
    + 'Iron Man \n'

// ES6
let lastWords = `
    I
    am
    Iron Man
`

In ES6, we do not need to use the escape sequence "\ n" to feed the line.

// ES5
function greet(name){
    return 'Hello ' + name + '!'
}

// ES6
function greet(name){
    return `Hello ${name}!`
}

In ES6, we don’t need to use string concatenation to combine text with a variable: we can use the expression $ {expr} to get the value of the variable.

46. ​​What is Object Destructuring?


Destructuring is a relatively new way of obtaining (retrieving) the values ​​of an object or array.

Let's say we have an object like this:

const employee = {
    firstName: 'Marko',
    lastName: 'Polo',
    position: 'Software Developer',
    yearHired: 2017
}

Previously, to create the properties of an object, we created variables for each property. It was very boring and very annoying:

var firstName = employee.firstName
var lastName = employee.lastName
var position = employee.position
var yearHired = employee.yearHired

Using destructuring makes the code cleaner and takes less time. The destructuring syntax is as follows: we enclose the object properties that we want to receive in curly brackets ({}), and if we are talking about an array, in square brackets ([]):

let { firstName, lastName, position, yearHired } = employee

To change the variable name, use "propertyName: newName":

let { firstName: fName, lastName: lName, position, yearHired } = employee

To assign default values ​​to variables, use "propertyName = 'defaultValue'":

let { firstName = 'Mark', lastName: lName, position, yearHired } = employee

47. What are Modules?


Modules allow you to combine (use) code from different files and save us from having to keep all the code in one large file. Before modules appeared in JS, there were two popular module systems for supporting code:

  • CommonJS - Nodejs
  • AMD (AsyncronousModuleDefinition) - Browsers

The syntax of the modules is very simple: we use import to import functionality or values ​​from another file or files, and export to export.

Export functionality to another file (named export):

// ES5 CommonJS - helpers.js
exports.isNull = function(val){
    return val === null
}

exports.isUndefined = function(val){
    return val === undefined
}

exports.isNullOrUndefined = function(val){
    return exports.isNull(val) || exports.isUndefined(val)
}

// ES6 
export function isNull(val){
    return val === null;
}

export function isUndefined(val) {
    return val === undefined;
}

export function isNullOrUndefined(val) {
    return isNull(val) || isUndefined(val);
}

Import functionality into another file:

// ES5 CommonJS - index.js
const helpers = require('./helpers.js')
const isNull = helpers.isNull
const isUndefined = helpers.isUndefined
const isNullOrUndefined = helpers.isNullOrUndefined

//    
const { isNull, isUndefined, isNullOrUndefined } = require('./helpers.js')

// ES6 
import * as helpers from './helpers.js' // helpers -  

// 
import { isNull, isUndefined, isNullOrUndefined as isValid} from './helpers.js' //  "as"  

Default Export:

// ES5 CommonJS - index.js
class Helpers {
    static isNull(val){
        return val === null
    }

    static isUndefined(val){
        return val === undefined
    }

    static isNullOrUndefined(val){
        return this.isNull(val) || this.isUndefined(val)
    }
}

module.exports = Helpers

// ES6 
class Helpers {
    static isNull(val){
        return val === null
    }

    static isUndefined(val){
        return val === undefined
    }

    static isNullOrUndefined(val){
        return this.isNull(val) || this.isUndefined(val)
    }
}

export default Helpers

Import:

// ES5 CommonJS - index.js
const Helpers = require('./helpers.js')
console.log(Helpers.isNull(null))

// ES6 
import Helpers from './helpers.js'
console.log(Helpers.isNull(null))

This is the basic use of modules. I did not go into details, because my post is already too large.

48. What is a Set object?


The Set object allows you to store unique values, primitives, and object references. Once again: only unique values ​​can be added to Set. It checks the values ​​stored in it using the SameZeroValue algorithm.

A Set instance is created using the Set constructor. We can also pass it some values ​​when creating:

const set1 = new Set()
const set2 = new Set(['a','b','c','d','d','e']) //  "d"  

We can add values ​​to Set using the add method. Since the add method is returnable, we can use a chain of calls:

set2.add('f')
set2.add('g').add('h').add('i').add('j').add('k').add('k') //  "k"  

We can delete values ​​from Set using the delete method:

set2.delete('k') // true
set2.delete('z') // false,    set2   

We can check for a property in Set using the has method:

set2.has('a') // true
set2.has('z') // false

To get the length of Set, use the size method:

set2.size // 10

The clear method clears Set:

set2.clear() // 

We can use Set to remove duplicate values ​​in an array:

const nums = [1,2,3,4,5,6,6,7,8,8,5]
const uniqNums = [...new Set(nums)] // [1,2,3,4,5,6,7,8]

49. What is a Callback Function?


The callback function is a function whose call is postponed for the future (occurs under certain conditions, for example, when an event occurs).

const btnAdd = document.getElementById('btnAdd')

btnAdd.addEventListener('click', function clickCallback(e)){
    //   
}

In the example, we are waiting for a “click” event on an element with the identifier “btnAdd”. By click, the clickCallback function is called. The callback function adds some functionality to the data or event. The reduce, filter, and map methods are passed a callback function as the second argument. A good analogy to callback is the following situation: you call someone, he does not answer, you leave him a message and wait for him to call back. A call or message is an event or data, and a callback is the expectation (anticipation) of a return call.

50. What are Promises?


Promises are one way of working with asynchronous code in JS. They return the result of an asynchronous operation. Promises were invented to solve the problem of the so-called hell of callback functions.

fs.readFile('somefile.txt', function(e, data){
    if(e){
        console.log(e)
    }
    console.log(data)
})

The problems with this approach begin when we need to add another asynchronous operation to the first (inside the first), then another, etc. As a result, we get a messy and unreadable code:

fs.readFile('somefile.txt', function(e,data){
    // 
    fs.readFile('directory', function(e, files){
        // 
        fs.mkdir('directory', function(e){
            // 
        })
    })
})

And here is what it looks like with promises:

promReadFile('file/path')
.then(data => {
    return promReaddir('directory')
})
.then(data => {
    return promMkdir('directory')
})
.catch(e => {
    console.error(e)
})

Promise has four conditions:

  • Waiting is the initial state of a promise. The result of the promise is unknown because the operation is not completed.
  • Done - Asynchronous operation completed, there is a result.
  • Rejected - asynchronous operation failed, there is a reason.
  • Completed - completed or rejected.

The Promise constructor accepts resolve and reject as parameters. In resolve, the result of the operation is recorded, in reject, the reason for the failure of the operation. The result can be processed in the .then method, the error can be processed in the .catch method. The .then method also returns a promise, so we can use a chain consisting of several .then.

const myPromiseAsync = (...args) => {
    return new Promise((resolve, reject) => {
        doSomeAsync(...args, (error, data) => {
            if(error){
                reject(error)
            } else{
                resolve(data)
            }
        })
    })
}

myPromiseAsync()
.then(result => {
    console.log(result)
})
.catch(reason => {
    console.error(reason)
})

We can create a helper function to convert an asynchronous operation from callback to a promise. It will work like util from Node.js (“promisification”):

const toPromise = (asyncFuncWithCallback) => {
    return (...args) => {
        return new Promise((res, rej) => {
            asyncFuncWithCallback(...args, (e, result) => {
                return e ? rej(e) : res(result)
            })
        })
    }
}

const promiseReadFile = toPromise(fs.readFile)

promiseReadFile('file/path')
.then((data) => {
    console.log(data)
})
.catch(e => console.error(e))

You can read more about promises here and here .

51. What is async / await?


Async / await is a relatively new way to write asynchronous (non-blocking) code in JS. They are wrapped in a promise. It makes code more readable and clean than promises and callback functions. However, to use async / await, you need to know the promises well.

// 
function callApi(){
    return fetch('url/to/api/endpoint')
    .then(resp => resp.json())
    .then(data => {
        //   
    }).catch(err => {
        //   
    })
}

// async/await
//     try/catch
async function callApi(){
    try{
        const resp = await fetch('url/to/api/endpoint')
        const data = await res.json()
        //   
    } catch(e){
        //   
    }
}

Remember: using the async keyword before a function forces it to return a promise:

const giveMeOne = async () = 1

giveMeOne()
.then((num) => {
    console.log(num) // 1
})

The await keyword can only be used inside an asynchronous function. Using await inside another function will result in an error. Await waits for the expression to finish on the right to return its value before executing the next line of code.

const giveMeOne = async() => 1

function getOne(){
    try{
        const num = await giveMeOne()
        console.log(num)
    } catch(e){
        console.log(e)
    }
}
// Uncaught SyntaxError: await is only valid in an async function

async function getTwo(){
    try{
        const num1 = await giveMeOne()
        const nm2 = await giveMeOne()
        return num1 + num2
    } catch(e){
        console.log(e)
    }
}

await getTwo() // 2

Read more about async / await here and here .

52. What is the difference between a spread operator and a rest operator?


The spread and rest statements have the same syntax ("..."). The difference lies in the fact that with the help of spread we transfer or spread the data of the array to other data, and with the help of rest we get all the parameters of the function and put them into the array (or we extract some of the parameters).

function add(a, b){
    return a + b
}

const nums = [5, 6]
const sum = add(...nums)
console.log(sum) // 11

In this example, we use spread when calling the add function with the nums array data. The value of the variable “a” will be 5, b = 6, sum = 11.

function add(...rest){
    return rest.reduce((total, current) => total + current)
}

console.log(add(1, 2)) // 3
console.log(add(1, 2, 3, 4, 5)) // 15

Here we call the add function with any number of arguments. Add returns the sum of these arguments.

const [first, ...others] = [1, 2, 3, 4, 5]
console.log(first) // 1
console.log(others) // [2, 3, 4, 5]

In this example, we use rest to put any number of parameters except the first one into the others array.

53. What are the Default Parameters?


This is a relatively new way of defining default variable values.

// ES5
function add(a,b){
    a = a || 0
    b = b || 0
    return a + b
}

// ES6
function add(a = 0, b = 0){
    return a + b
}
//      "a"  "b" - ,    0
add(1) // 1

You can use destructuring:

function getFirst([first, ...rest] = [0, 1]){
    return first
}

getFirst() // 0
getFirst([10,20,30]) // 10

function getArr({ nums } = { nums: [1,2,3,4] }){
    return nums
}

getArr // [1,2,3,4]
getArr({nums:[5,4,3,2,1]}) // [5,4,3,2,1]

We can even use the default parameters declared in the same place:

function doSomethingWithValue(value = 'Hello World', callback = () => { console.log(value) }){
    callback()
}
doSomethingWithValue() // Hello World

54. What is an object wrapper (Wrapper Objects)?


The primitives string, number, and boolean have properties and methods, despite the fact that they are not objects:

let name = 'marko'

console.log(typeof name) // string
console.log(name.toUpperCase()) // MARKO

Name is a string (primitive type) that has no properties and methods, but when we call the toUpperCase () method, this leads not to an error, but to “MARKO”.

The reason for this behavior is that name is temporarily converted to an object. Each primitive, except null and undefined, has a wrapper object. Such objects are String, Number, Boolean, Symbol, and BigInt. In our case, the code takes the following form:

console.log(new String(name).toUpperCase()) // MARKO

A temporary object is discarded upon completion of work with a property or method.

55. What is the difference between Implicit and Explicit Coercion?


Implicit conversion is a way of casting a value to another type without our knowledge (participation).

Suppose we have the following:

console.log(1 + '6')
console.log(false + true)
console.log(6 * '2')

The result of the first console.log will be 16. In other languages, this would lead to an error, but in JS 1 it is converted to a string and concatenated (attached) from 6. We did nothing, the conversion occurred automatically.

The result of the second console.log will be 1. False was converted to 0, true to 1. 0 + 1 = 1.

The result of the third console.log will be 12. Line 2 was converted to a number before multiplying by 6.

Explicit conversion implies our participation in casting the value to another type:

console.log(1 + parseInt('6'))

In this example, we use parseInt to cast string 6 to a number, then add up the two numbers and get 7.

56. What is NaN? How to check if the value is NaN?


NaN or Not A Number (not a number) is the value obtained as a result of performing a numerical operation on a non-numerical value:

let a

console.log(parseInt('abc'))
console.log(parseInt(null))
console.log(parseInt(undefined))
console.log(parseInt(++a))
console.log(parseInt({} * 10))
console.log(parseInt('abc' - 2))
console.log(parseInt(0 / 0))
console.log(parseInt('10a' * 10))

JS has a built-in isNaN method that allows you to check if the value is NaN, but it behaves quite strangely:

console.log(isNaN()) // true
console.log(isNaN(undefined)) // true
console.log(isNaN({})) // true
console.log(isNaN(String('a'))) // true
console.log(isNaN(() => { })) // true

The result of all console.log is true, despite the fact that none of the values ​​is NaN.

ES6 recommends using the Number.isNaN method to check if the value is NaN. We can also write an auxiliary function to solve the problem of “NaN inequality for itself”:

function checkIsNan(value){
    return value !== value
}

57. How to check if a value is an array?


To do this, use the Array.isArray method:

console.log(Array.isArray(5)) // false
console.log(Array.isArray('')) // false
console.log(Array.isArray()) // false
console.log(Array.isArray(null)) // false
console.log(Array.isArray( {length: 5 })) // false
console.log(Array.isArray([])) // true

If the environment in which you work does not support this method, you can use the following polyfile:

function isArray(value){
    return Object.prototype.toString.call(value) === '[object Array]'
}

58. How to check that a number is even, without using modulo division or division with remainder (operator "%")?


To solve this problem, you can use the operator "&" (binary and). The & operator compares operands as binary values.

function isEven(num){
    if(num & 1){
        return false
    } else{
        return true
    }
}

0 in the binary notation is 000
1 - this is 001
2 - 010
3 - 011
4 - 100
5 - 101
6 - 110
7 - 111
, etc.



Console.log (5 & 1) will return 1. First, the & operator converts both numbers to binary values, 5 turns into 101, 1 turns into 001. Then a bitwise comparison is made:



Compare 1 and 0, we get 0.
Compare 0 and 0 , we get 0.
Compare 1 and 1, we get 1.
Convert the binary value to an integer, we get 1.

If this information seems too complicated for you, we can solve the problem using the recursive function:

function isEven(num){
    if(num < 0 || num === 1) return false
    if(num == 0) return true
    return isEven(num - 2)
}

59. How to determine the presence of a property in an object?


There are three ways to do this.

The first way is to use the in operator:

const o = {
    'prop': 'bwahahah',
    'prop2': 'hweasa'
}

console.log('prop' in o) // true
console.log('prop1' in o) // false

The second is to use the hasOwnProperty method:

console.log(o.hasOwnProperty('prop2')) // true
console.log(o.hasOwnProperty('prop1')) // false

The third is the index notation of the array:

console.log(o['prop']) // bwahahah
console.log(o['prop1']) // undefined

60. What is AJAX?


AJAX or Asyncronous JavaScript and XML is a set of interconnected technologies that allow you to work with data in asynchronous mode. This means that we can send data to the server and receive data from it without reloading the web page.

AJAX uses the following technologies:
HTML - web page structure.
CSS - web page styles.
JavaScript - page behavior and work with the DOM.
XMLHttpRequest API - sending and receiving data from the server.
PHP, Python, Nodejs - some kind of server language.

61. How to create an object in JS?


Object literal:

const o = {
    name: 'Mark',
    greeting(){
        return `Hi, I'm ${this.name}`
    }
}

o.greeting // Hi, I'm Mark

Constructor function:

function Person(name){
    this.name = name
}

Person.prototype.greeting = function(){
    return `Hi, I'm ${this.name}`
}

const mark = new Person('Mark')

mark.greeting() // Hi, I'm Mark

Object.create Method:

const n = {
    greeting(){
        return `Hi, I'm ${this.name}`
    }
}

const o = Object.create(n)

o.name = 'Mark'

console.log(o.greeting) // Hi, I'm Mark

62. What is the difference between the methods Object.freeze and Object.seal?


The difference is that when using the Object.freeze method, we cannot change or edit the properties of the object, and when using Object.seal we have such an opportunity.

63. What is the difference between the in operator and the hasOwnProperty method?


The difference is that the "in" operator checks for the presence of a property not only in the object itself, but also in its prototypes, and the hasOwnProperty method - only in the object.

console.log('prop' in o) // true
console.log('toString' in o) // true

console.log(o.hasOwnProperty('prop')) // true
console.log(o.hasOwnProperty('toString')) // false

64. What techniques of working with asynchronous code in JS do you know?


  • Callbacks
  • Promises (Promises).
  • Async / await.
  • Libraries like async.js, blueprint, q, co.

65. What is the difference between a normal function and a functional expression?


Let's say we have the following:

hoistedFunc()
notHoistedFunc()

function hoistedFunc(){
    console.log('I am hoisted')
}

var notHoistedFunc = function(){
    console.log('I will not be hoisted!')
}

A call to notHoistedFunc will result in an error, but a call to hoistedFunc does not, because hoistedFunc “pops up”, rises to the global scope, but notHoistedFunc does not.

66. How to call a function in JS?


In JS, there are 4 ways to call a function. The call defines the value of this or the "owner" of the function.

Call as a function. If a function is called as a method, constructor, or using the apply or call methods, then it is called as a function. The owner of such a function is the window object:

function add(a,b){
    console.log(this)
    return a + b
}

add(1,5) // window, 6

const o = {
    method(callback){
        callback()
    }
}

o.method(function(){
    console.log(this) // window
})

Call as a method. When a function is a property of an object, we call it a method. When a method is called, the this object becomes the object of this method:

const details = {
    name: 'Marko',
    getName(){
        return this.name
    }
}

details.getName() // Marko,  this   details

Call as constructor. When a function is called using the “new” keyword, we call that function a constructor. This creates an empty object, which is the value of this:

function Employee(name, position, yearHired){
    //   ,   this
    // this = {}
    this.name = name
    this.position = position
    this.yearHired = yearHired
    //   Employee.prototype   this,    
}

const emp = new Employee('Marko Polo', 'Software Development', 2017)

A call using the apply or call methods. We use these methods when we want to explicitly determine the value of this or the owner of a function:

const obj1 = {
    result: 0
}

const obj2 = {
    result: 0
}

function reduceAdd(){
    let result = 0
    for(let i = 0, len = arguments.length; i < len; i++){
        result += arguments[i]
    }
    this.result = result
}

reduceAdd.apply(obj1, [1,2,3,4,5]) //  this  obj1
reduceAdd.call(obj2, 1,2,3,4,5) //  this  obj2

67. What is memorization or memoization?


Memoization is the technique of creating a function that can remember previously calculated results or values. The advantage of memoization is that we avoid re-executing a function with the same arguments. The disadvantage is that we are forced to allocate additional memory to save the results.

68. How would you implement the auxiliary function of memorization?


function memoize(fn){
    const cache = {}
    return function(param){
        if(cache[param]){
            console.log('cached')
            return cache[param]
        } else{
            let result = fn(param)
            cache[param] = result
            console.log('not cached')
            return result
        }
    }
}

const toUpper = (str = '') => str.toUpperCase()

const toUpperMemoized = memoize(toUpper)

toUpperMemoized('abcdef')
toUpperMemoized('abcdef') //  

We implemented the memoization function with one argument. Let's make it "multi-argument":

const slice = Array.prototype.slice
function memoize(fn){
    const cache = {}
    return (...args) => {
        const params = slice.call(args)
        console.log(params)
        if(cache[params]){
            console.log('cached')
            return cache[params]
        } else{
            let result = fn(...args)
            cache[params] = result
            console.log('not cached')
            return result
        }
    }
}
const makeFullName = (fName, lName) => `${fName} ${lName}`
const reduceAdd = (numbers, startValue = 0) => numbers.reduce((total, cur) => total + cur, startValue)

const memoizedFullName = memoize(makeFullName)
const memoizeReduceAdd = memoize(reduceAdd)

memoizedFullName('Marko', 'Polo')
memoizedFullName('Marko', 'Polo') //  

memoizeReduceAdd([1,2,3,4],5)
memoizeReduceAdd([1,2,3,4],5) //  

69. Why typeof null returns object? How to check if a value is null?


typeof null == 'object' will always return true for historical reasons. There was a proposal to fix this error by changing typeof null = 'object' to typeof null = 'null', but it was rejected in the interest of maintaining backward compatibility (such a change would entail a large number of errors).

To check whether the value is null, you can use the strict equality operator (===):

function isNull(value){
    return value === null
}

70. What is the “new” keyword used for?


The keyword “new” is used in constructor functions to create a new object (a new instance of the class).

Let's say we have a code like this:

function Employee(name, position, yearHired){
    this.name = name
    this.position = position
    this.yearHired = yearHired
}

const emp = new Employee('Marko Polo', 'Software Development', 2017)

The keyword "new" does 4 things:

  1. Creates an empty object.
  2. Binds the this value to it.
  3. A function inherits from functionName.prototype.
  4. Returns this unless otherwise specified.

Source: https://habr.com/ru/post/undefined/


All Articles