Questions d'entretiens chez Javascript

Bonjour mes amis!

J'espère que cet article sera utile aux développeurs novices et expérimentés.

Dans les questions qui m'ont paru plus difficiles que d'autres, des références à de la littérature supplémentaire sont données.

Je serais reconnaissant pour les commentaires détaillés. Tous les commentaires seront pris en compte lors de l'édition de l'article.

Alors allons-y.

Questions d'entretiens chez Javascript


Questions:
1. Quelle est la différence entre null et indéfini?
2. À quoi sert l'opérateur &&?
3. À quoi sert l'opérateur "||"?
4. L'utilisation de l'opérateur unaire plus (+) est-elle le moyen le plus rapide de convertir une chaîne en nombre?
5. Qu'est-ce qu'un DOM?
6. Qu'est-ce que la propagation d'événements?
7. Qu'est-ce que la bulle d'événements?
8. Qu'est-ce que la capture d'événements?
9. Quelle est la différence entre les méthodes event.preventDefault () et event.stopPropagation ()?
10. Comment apprendre à utiliser la méthode event.preventDefault ()?
11. Pourquoi obj.someprop.x conduit-il à une erreur?
12. Qu'est-ce qu'une cible d'événement ou un élément cible (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. Quelles techniques de travail avec du code asynchrone dans JS connaissez-vous?
65. Quelle est la différence entre une fonction normale et une expression fonctionnelle?
66. Comment appeler une fonction dans JS?
67. Qu'est-ce que la mémorisation ou la mémorisation?
68. Comment mettriez-vous en œuvre la fonction auxiliaire de mémorisation?
69. Pourquoi typeof null renvoie un objet? Comment vérifier si une valeur est nulle?
70. À quoi sert le «nouveau» mot clé?

1. Quelle est la différence entre null et undefined?


Pour commencer, parlons de ce qu'ils ont en commun.

Premièrement, ils appartiennent à 7 "primitives" JS (types primitifs):

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

Deuxièmement, ce sont de fausses valeurs, c'est-à-dire le résultat de les convertir en booléen en utilisant Boolean () ou l'opérateur "!!" c'est faux:

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

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

D'accord, maintenant sur les différences.

undefined est la valeur par défaut:
  • une variable à laquelle aucune valeur n'a été affectée, c'est-à-dire une variable déclarée mais non initialisée;
  • une fonction qui ne renvoie rien de manière explicite, par exemple, console.log (1);
  • propriété inexistante de l'objet.

Dans ces cas, le moteur JS définit la valeur sur 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 est la "valeur d'aucune valeur". null est la valeur affectée explicitement à la variable. Dans l'exemple ci-dessous, nous obtenons null lorsque la méthode fs.readFile fonctionne sans erreur:

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

Lorsque nous comparons null et indéfini, nous obtenons la valeur true lors de l'utilisation de l'opérateur "==" et la valeur false lors de l'utilisation de l'opérateur "===". Pour savoir pourquoi cela se produit, voir ci-dessous.

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

2. À quoi sert l'opérateur &&?


L'opérateur && (logique et) recherche et renvoie la première fausse valeur ou le dernier opérande lorsque toutes les valeurs sont vraies. Il utilise un court-circuit pour éviter des coûts inutiles:

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

Avec l'instruction if:

const router: Router = Router()

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

Même chose avec l'opérateur &&:

const router: Router = Router()

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

3. À quoi sert l'opérateur "||"?


L'opérateur "||" (booléen ou) recherche et renvoie la première vraie valeur. Il utilise également un court-circuit. Cet opérateur a été utilisé pour affecter des paramètres par défaut dans les fonctions avant que les paramètres par défaut ne soient standardisés dans ES6.

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

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

logName() // Mark

4. L'utilisation de l'opérateur unaire plus (+) est-elle le moyen le plus rapide de convertir une chaîne en nombre?


Selon MDN , l'opérateur + est en effet le moyen le plus rapide pour convertir une chaîne en nombre, car il n'effectue aucune opération sur une valeur qui est un nombre.

5. Qu'est-ce qu'un DOM?


Le DOM ou Document Object Model est une interface de programmation d'application (API) pour travailler avec des documents HTML et XML. Lorsque le navigateur lit («analyse») le document HTML pour la première fois, il forme un objet volumineux, un objet vraiment volumineux basé sur le document - le DOM. Le DOM est une structure arborescente (arborescence de documents). Le DOM est utilisé pour interagir et changer la structure du DOM lui-même ou de ses éléments et nœuds individuels.

Disons que nous avons ce 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>

Le DOM de ce HTML ressemble à ceci:



En JS, le DOM est représenté par un objet Document. L'objet Document dispose d'un grand nombre de méthodes de travail avec les éléments, leur création, modification, suppression, etc.

6. Qu'est-ce que la propagation d'événements?


Lorsqu'un événement se produit dans un élément DOM, il ne se produit pas uniquement dans celui-ci. L'événement "se propage" de l'objet Window à l'élément qui l'a appelé (event.target). Dans ce cas, l'événement imprègne (affecte) séquentiellement tous les ancêtres de l'élément cible. Une propagation d'événement comporte trois étapes ou phases:
  1. Phase d'immersion (capture, interception) - un événement se produit dans l'objet Window et descend vers la cible de l'événement à travers tous ses ancêtres.
  2. La phase cible est lorsque l'événement atteint l'élément cible.
  3. Phase ascendante - un événement monte de event.target, traverse séquentiellement tous ses ancêtres et atteint l'objet Window.



En savoir plus sur la distribution des événements ici et ici .

7. Qu'est-ce qu'un popup d'événement?


Lorsqu'un événement se produit dans un élément DOM, il affecte non seulement cet élément. Un événement «apparaît» (comme une bulle d'air dans l'eau), passe de l'élément qui a provoqué l'événement (event.target) à son parent, puis monte encore plus haut, au parent du parent de l'élément, jusqu'à ce qu'il atteigne l'objet Window.

Disons que nous avons ce balisage:

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

Et un tel 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')
    })
})

La méthode addEventListener a un troisième paramètre facultatif - useCapture. Lorsque sa valeur est fausse (par défaut), l'événement commence par la phase de remontée. Lorsque sa valeur est vraie, l'événement commence par la phase d'immersion (pour les "écouteurs" d'événements attachés à la cible de l'événement, l'événement est dans la phase cible, et non dans les phases d'immersion ou de remontée. Les événements de la phase cible sont déclenchés par tous les écouteurs de l'élément dans l'ordre dans lequel ils ont été enregistrés quel que soit le paramètre useCapture - env. Si nous cliquons sur l'élément enfant, la console affichera: enfant, parent, grand-parent, html, document, fenêtre. Voici ce qu'est un popup d'événement.

8. Qu'est-ce qu'un événement d'immersion?


Lorsqu'un événement se produit dans un élément DOM, il se produit non seulement dans celui-ci. Dans la phase d'immersion, l'événement descend de l'objet Window vers la cible de l'événement à travers tous ses ancêtres.

Balisage:

<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)
})

La méthode addEventListener a un troisième paramètre facultatif - useCapture. Lorsque sa valeur est fausse (par défaut), l'événement commence par la phase de remontée. Lorsque sa valeur est vraie, l'événement commence par la phase de plongée. Si nous cliquons sur l'élément enfant, nous verrons ce qui suit dans la console: fenêtre, document, html, grand-parent, parent, enfant. C'est l'immersion de l'événement.

9. Quelle est la différence entre les méthodes event.preventDefault () et event.stopPropagation ()?


La méthode event.preventDefault () désactive le comportement par défaut d'un élément. Si vous utilisez cette méthode dans l'élément de formulaire, cela empêchera la soumission du formulaire. Si vous l'utilisez dans le menu contextuel, le menu contextuel sera désactivé (cette méthode est souvent utilisée dans les touches pour redéfinir le clavier, par exemple, lors de la création d'un lecteur de musique / vidéo ou d'un éditeur de texte - env. La méthode event.stopPropagation () désactive la propagation de l'événement (son ascension ou son immersion).

10. Comment apprendre à utiliser la méthode event.preventDefault ()?


Pour ce faire, nous pouvons utiliser la propriété event.defaulPrevented, qui renvoie un booléen qui sert d'indicateur d'application à l'élément de la méthode event.preventDefault.

11. Pourquoi obj.someprop.x conduit-il à une erreur?



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

La réponse est évidente: nous essayons d'accéder à la propriété x de la propriété someprop, qui n'est pas définie. obj .__ proto __.__ proto = null, donc undefined est retourné et undefined n'a pas la propriété x.

12. Qu'est-ce qu'une cible d'événement ou un élément cible (event.target)?


En termes simples, event.target est l'élément dans lequel l'événement se produit, ou l'élément qui a déclenché l'événement.

Nous avons le balisage suivant:

<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>

Et un simple JS:

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

Nous avons attaché un «auditeur» à la div extérieure. Cependant, si nous cliquons sur le bouton, nous obtenons la disposition de ce bouton dans la console. Cela nous permet de conclure que l'élément qui a provoqué l'événement est le bouton lui-même, et non les divisions externes ou internes.

13. Quel est le but actuel de l'événement (event.currentTarget)?


Event.currentTarget est l'élément auquel l'écouteur d'événement est attaché.

Balisage similaire:

<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>

Et un JS légèrement modifié:

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

Nous avons attaché l'auditeur à la div externe. Partout où nous cliquons, que ce soit un bouton ou l'une des divisions internes, dans la console, nous obtenons toujours la disposition de la division externe. Cela nous permet de conclure que event.currentTarget est l'élément auquel l'écouteur d'événement est attaché.

14. Quelle est la différence entre les opérateurs "==" et "==="?


La différence entre l'opérateur == (égalité abstraite ou non stricte) et l'opérateur === (égalité stricte) est que le premier compare les valeurs après leur conversion ou conversion en un type (Coersion), et le second - sans une telle conversion .

Creusons plus profondément. Et d'abord, parlons de la transformation.

Une conversion est un processus de conversion d'une valeur en un autre type, ou plutôt, un processus de conversion des valeurs comparées en un type. Lors de la comparaison, l'opérateur "==" produit la soi-disant comparaison implicite. L'opérateur "==" effectue certaines opérations avant de comparer deux valeurs.

Supposons que nous comparons x et y.

L'algorithme est le suivant:

  1. Si x et y sont du même type, la comparaison est effectuée à l'aide de l'opérateur "===".
  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.

N'oubliez pas: pour convertir un objet en une "primitive", la méthode toPrimitive utilise d'abord la méthode valueOf, puis la méthode toString.

Exemples:



Tous les exemples renvoient true.

Le premier exemple est la première condition de l'algorithme.
Le deuxième exemple est la quatrième condition.
Le troisième est le deuxième.
Le quatrième est le septième.
Cinquième-huitième.
Et le dernier est le dixième.



Si nous utilisons l'opérateur "===", tous les exemples sauf le premier renverront false, car les valeurs de ces exemples sont de types différents.

15. Pourquoi le résultat de la comparaison de deux objets similaires est-il faux?


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

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

Dans JS, les objets et les primitives sont comparés différemment. Les primitives sont comparées par valeur. Objets - par référence ou adresse en mémoire où la variable est stockée. C'est pourquoi le premier console.log renvoie false et le second retourne true. Les variables "a" et "c" se réfèrent au même objet, tandis que les variables "a" et "b" se réfèrent à des objets différents avec les mêmes propriétés et valeurs.

16. À quoi sert l'opérateur "!!"?


L'opérateur "!!" (double négation) conduit la valeur à sa droite à une valeur logique.

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. Comment écrire plusieurs expressions sur une seule ligne?


Pour cela, nous pouvons utiliser l'opérateur "," (virgule). Cet opérateur "se déplace" de gauche à droite et renvoie la valeur de la dernière expression ou opérande.

let x = 5

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

function addFive(num) {
    return num + 5
}

Si nous imprimons la valeur de x sur la console, nous obtenons 27. Premièrement, nous augmentons la valeur de x de un (x = 6). Ensuite, nous appelons la fonction addFive () avec le paramètre 6, à laquelle nous ajoutons 5 (x = 11). Après cela, nous multiplions la valeur de x par 2 (x = 22). Ensuite, soustrayez 5 (x = 17). Et enfin, ajoutez 10 (x = 27).

18. Qu'est-ce que le levage?


Lift est un terme qui décrit la montée d'une variable ou d'une fonction dans une portée globale ou fonctionnelle.

Pour comprendre ce qu'est le levage, vous devez comprendre le contexte d'exécution.

Le contexte d'exécution est l'environnement dans lequel le code est exécuté. Le contexte d'exécution comporte deux phases - la compilation et l'exécution elle-même.

Compilation. Dans cette phase, les expressions fonctionnelles et les variables déclarées à l'aide du mot-clé "var" avec la valeur indéfinie montent tout en haut de la portée globale (ou fonctionnelle) (comme si nous passions au début de notre code. Cela explique pourquoi nous pouvons appeler des fonctions avant qu'elles annonces - env.

Performance. Dans cette phase, les variables reçoivent des valeurs et les fonctions (ou méthodes d'objets) sont appelées ou exécutées.

N'oubliez pas: seules les expressions fonctionnelles et les variables déclarées à l'aide du mot-clé «var» sont levées. Les fonctions ordinaires et les fonctions fléchées, ainsi que les variables déclarées à l'aide des mots-clés «let» et «const», ne sont pas déclenchées.

Supposons que nous ayons un code comme celui-ci:

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

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

var y

Nous obtenons indéfini, 1 et «Bonjour Mark!».

Voici à quoi ressemble la phase de compilation:

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

var y //  undefined

//    

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

Une fois la phase de compilation terminée, la phase d'exécution commence lorsque les variables reçoivent des valeurs et des fonctions sont appelées.

Pour en savoir plus sur le levage, cliquez ici .

19. Qu'est-ce qu'une portée?


Une portée est un endroit où (ou d'où) nous avons accès à des variables ou des fonctions. JS nous avons trois types de portées: globale, fonctionnelle et bloc (ES6).

Portée globale - les variables et fonctions déclarées dans l'espace de noms global ont une portée globale et sont accessibles de n'importe où dans le code.

//   
var g = 'global'

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

Portée fonctionnelle (portée d'une fonction) - les variables, fonctions et paramètres déclarés à l'intérieur d'une fonction ne sont disponibles qu'à l'intérieur de cette fonction.

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) //  

Portée du bloc - les variables (déclarées à l'aide des mots clés "let" et "const") à l'intérieur du bloc ({}) ne sont disponibles qu'à l'intérieur.

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

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

Une étendue est également un ensemble de règles par lesquelles une variable est recherchée. Si la variable n'existe pas dans la portée actuelle, sa recherche est effectuée plus haut dans la visibilité externe de la portée actuelle. S'il n'y a pas de variable dans la portée externe, sa recherche se poursuit jusqu'à la portée globale. Si une variable est trouvée dans la portée globale, la recherche s'arrête; sinon, une exception est levée. La recherche est effectuée par le plus proche des zones de visibilité actuelles et s'arrête à la recherche de la variable. C'est ce qu'on appelle la chaîne de portée.

//   
//    ->    ->   

//   
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. Qu'est-ce qu'une fermeture (fermetures)?


C'est probablement la question la plus difficile de la liste. Je vais essayer d'expliquer comment je comprends la clôture.

En fait, la fermeture est la capacité d'une fonction à créer, au moment de la création, la mémorisation de références à des variables et des paramètres situés dans la portée actuelle, dans la portée de la fonction parent, dans la portée du parent de la fonction parent, et ainsi de suite dans la portée globale à l'aide de la chaîne de portée. En règle générale, la portée est déterminée lors de la création d'une fonction.

Les exemples sont un excellent moyen d'expliquer la fermeture:

//   
var globalVar = 'abc'

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

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

Dans cet exemple, lorsque nous déclarons une fonction, la portée globale fait partie de la fermeture.



La variable «globalVar» n'a pas d'importance dans l'image, car sa valeur peut changer selon l'endroit et le moment où la fonction sera appelée. Mais dans l'exemple ci-dessus, globalVar aura la valeur «abc».

Maintenant, l'exemple est plus compliqué:

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')



Le résultat est «devinez l'extérieur intérieur». L'explication est la suivante: lorsque nous appelons la fonction externalFunc et affectons à la variable "x" la valeur renvoyée par la fonction innerFunc, le paramètre "externalParam" est égal à "external". Malgré le fait que nous ayons assigné la variable «externalVar» à «external-2», cela s'est produit après avoir appelé la fonction externalFunc, qui «a réussi» à trouver la valeur de la variable «externalVar» dans la chaîne de portée, cette valeur était «external». Lorsque nous appelons "x", qui fait référence à innerFunc, la valeur de "innerParam" est "inner", car nous transmettons cette valeur comme paramètre lors de l'appel de "x". globalVar a une valeur de «guess» car nous lui avons attribué cette valeur avant d'appeler «x».

Un exemple de malentendu sur un 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
}

Ce code ne fonctionne pas comme prévu. La déclaration d'une variable à l'aide du mot clé var rend cette variable globale. Après avoir ajouté des fonctions au tableau arrFunc, la valeur de la variable globale «i» devient «5». Par conséquent, lorsque nous appelons la fonction, elle renvoie la valeur de la variable globale «i». Une fermeture stocke une référence à une variable, pas sa valeur au moment de la création. Ce problème peut être résolu en utilisant IIFE ou en déclarant une variable en utilisant le mot clé "let".

En savoir plus sur la fermeture ici et ici .

21. Quelles valeurs dans JS sont fausses?


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

Faux sont des valeurs dont la conversion en valeur booléenne est fausse.

22. Comment vérifier si une valeur est fausse?


Utilisez la fonction booléenne ou l'opérateur "!!" (deux fois non).

23. À quoi sert la directive d'utilisation stricte?


«Use strict» est une directive ES5 qui force tout notre code ou le code d'une fonction individuelle à s'exécuter en mode strict. Le mode strict introduit certaines restrictions sur l'écriture de code, évitant ainsi les erreurs dans les premières étapes.

Voici les limites du mode strict.

Vous ne pouvez pas affecter de valeurs ou accéder à des variables non déclarées:

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

Il est interdit d'attribuer des valeurs globales aux variables en lecture seule ou en écriture seule:

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

Vous ne pouvez pas supprimer la propriété "undeletable" d'un objet:

'use strict'
const obj = {}

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

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

La duplication des paramètres est interdite:

'use strict'

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

Vous ne pouvez pas créer de fonctions à l'aide de la fonction eval:

'use strict'

eval('var x = 1')

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

La valeur par défaut pour cela n'est pas définie:

'use strict'

function showMeThis() {
    return this
}

showMeThis() // undefined

… etc.

24. Qu'est-ce que cela signifie?


Cela fait généralement référence à la valeur de l'objet qui exécute ou appelle actuellement la fonction. «En ce moment» signifie que la valeur de ceci varie en fonction du contexte d'exécution, où nous l'utilisons.

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

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

Dans ce cas, la méthode getName renvoie this.name, et cela fait référence à carDetails, l'objet dans lequel getName est exécuté, qui est son "propriétaire".

Ajoutez trois lignes après console.log:

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

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

Le deuxième console.log produit un Ford Ranger, et c'est bizarre. La raison de ce comportement est que le "propriétaire" de getCarName est l'objet fenêtre. Les variables déclarées avec le mot clé var dans la portée globale sont écrites dans les propriétés de l'objet window. ceci dans la portée globale fait référence à l'objet window (sauf s'il s'agit d'un mode strict).

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

Dans cet exemple, this et window font référence au même objet.

Une façon de résoudre ce problème consiste à utiliser l'appel ou à appliquer des méthodes:

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

Appelez et appliquez prendre comme premier argument un objet qui en sera la valeur à l'intérieur de la fonction.

Dans IIFE, les fonctions créées dans la portée globale, les fonctions anonymes et les fonctions internes des méthodes d'un objet, la valeur par défaut est l'objet window.

(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
})

Il existe deux façons d'obtenir Marko Polo.

Tout d'abord, nous pouvons stocker la valeur de ceci dans une variable:

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

Deuxièmement, nous pouvons utiliser la fonction flèche:

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

Les fonctions fléchées n'ont pas cette valeur propre. Ils copient le sens de cela à partir de l'environnement lexical externe.

25. Qu'est-ce qu'un prototype d'objet?


En résumé, un prototype est un plan (diagramme ou projet) d'un objet. Il est utilisé comme solution de rechange pour les propriétés et méthodes existantes dans cet objet. C'est également l'un des moyens d'échanger des propriétés et des fonctionnalités entre des objets. Il s'agit du concept de base de l'héritage de prototype dans JS.

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

Bien que l'objet «o» ne possède pas de propriété toString, l'accès à cette propriété ne provoque pas d'erreur. Si une propriété spécifique n'est pas dans l'objet, sa recherche s'effectue d'abord dans le prototype de l'objet, puis dans le prototype du prototype de l'objet, et ainsi de suite jusqu'à ce que la propriété soit trouvée. C'est ce qu'on appelle la chaîne prototype. Au sommet de la chaîne de prototypes se trouve Object.prototype.

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

En savoir plus sur les prototypes et l'héritage ici et ici .

26. Qu'est-ce que l'IIFE?


IIFE ou expression de fonction immédiatement invoquée est une fonction qui est appelée ou exécutée immédiatement après sa création ou sa déclaration. Pour créer IIFE, vous devez encapsuler la fonction entre parenthèses (l'opérateur de regroupement), la transformer en une expression, puis l'appeler à l'aide d'une autre parenthèse. Il ressemble à ceci: (function () {}) ().

(function( ) { }( ))

(function( ) { })( )

(function named(params) { })( )

(( ) => { })

(function(global) { })(window)

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

Tous ces exemples sont valides. L'avant-dernier exemple montre que nous pouvons transmettre des paramètres à l'IFEF. Le dernier exemple montre que nous pouvons stocker le résultat de IIFE dans une variable.

La meilleure utilisation de IIFE est d'exécuter des fonctions de configuration d'initialisation et d'éviter les conflits de noms avec d'autres variables dans la portée globale (pollution de l'espace de noms global). Nous donnons un exemple.

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

Nous avons un lien vers la bibliothèque somelibrary.js, qui fournit certaines fonctions globales que nous pouvons utiliser dans notre code, mais il existe deux méthodes dans cette bibliothèque, createGraph et drawGraph, que nous n'utilisons pas car elles contiennent des erreurs. Et nous voulons implémenter ces fonctions nous-mêmes.

Une façon de résoudre ce problème est de changer la structure de nos scripts:

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

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

Ainsi, nous redéfinissons les méthodes fournies par la bibliothèque.

La deuxième façon consiste à changer les noms de nos fonctions:

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

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

La troisième façon consiste à utiliser IIFE:

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

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

Dans cet exemple, nous créons une variable utilitaire qui contient le résultat IIFE, qui renvoie un objet contenant les méthodes createGraph et drawGraph.

Voici un autre problème qui peut être résolu avec 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)
    })
}

Supposons que nous ayons un élément ul avec une classe de groupe de listes contenant 5 éléments enfants li. Et nous voulons afficher la valeur «i» dans la console lorsque vous cliquez sur un «li» distinct. Cependant, au lieu de cela, la console affiche toujours 5. Le défaut est tout le défaut.

Une solution est l'IFEF:

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)
}

La raison pour laquelle ce code fonctionne comme prévu est parce que IIFE crée une nouvelle étendue à chaque itération, et nous écrivons la valeur «i» dans currentIndex.

27. À quoi sert la méthode Function.prototype.apply?


Appliquer est utilisé pour lier un objet spécifique à la valeur this de la fonction appelée.

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

function getMessage() {
    return this.message
}

getMessage.apply(details) // Hello World!

Cette méthode est similaire à Function.prototype.call. La seule différence est que dans apply, les arguments sont passés sous forme de tableau.

const person = {
    name: 'Marko Polo'
}

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

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

28. À quoi sert la méthode function.prototype.call?


L'appel est utilisé pour lier un objet spécifique à la valeur de cette fonction appelée.

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

function getMessage() {
    return this.message;
}

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

Cette méthode est similaire à Function.prototype.apply. La différence est que dans les appels, les arguments sont passés séparés par des virgules.

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

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

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

29. Quelle est la différence entre les méthodes d'appel et d'application?


La différence entre call et apply est la façon dont nous passons les arguments dans la fonction appelée. Dans Apply, les arguments sont passés sous forme de tableau, en appel, séparés par des virgules.

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. À quoi sert la méthode function.prototype.bind?


Bind renvoie une nouvelle fonction dont cette valeur est l'objet spécifié comme premier paramètre. Contrairement à bind, appelez et appliquez immédiatement la fonction.

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. Qu'est-ce que la programmation fonctionnelle et quelles fonctionnalités de JS nous permettent d'en parler en tant que langage de programmation fonctionnel?


La programmation fonctionnelle est un concept de programmation déclarative ou un exemple (modèle) de la façon dont les applications sont construites, comment les fonctions contenant des expressions qui calculent des valeurs sans changer les arguments qui leur sont transmis sont utilisées.

L'objet Array contient les méthodes de mappage, de filtrage et de réduction, qui sont les fonctions les plus connues dans le monde de la programmation fonctionnelle en raison de leur utilité et également parce qu'elles ne modifient pas le tableau, ce qui rend ces fonctions «propres». JS a également une fermeture et des fonctions d'ordre supérieur qui sont les caractéristiques d'un langage de programmation fonctionnel.

La méthode map renvoie un nouveau tableau avec des résultats de rappel pour chaque élément du tableau:

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

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

La méthode de filtrage crée un nouveau tableau avec tous les éléments qui satisfont la condition spécifiée dans le rappel:

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

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

La méthode de réduction effectue un rappel une fois pour chaque élément du tableau, à l'exception des vides, en prenant quatre arguments: la valeur initiale (ou la valeur du rappel précédent), la valeur de l'élément actuel, l'index actuel et le tableau itéré:

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

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

32. Que sont les fonctions d'ordre supérieur?


Une fonction d'ordre supérieur est une fonction qui renvoie une autre fonction ou accepte une autre fonction comme argument.

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

33. Pourquoi les fonctions de JS sont-elles appelées objets de première classe?


Les fonctions sont appelées objets de première classe car elles sont traitées comme toute autre valeur dans JS. Ils peuvent être affectés à des variables, être une propriété d'un objet (méthode), un élément d'un tableau, un argument à une autre fonction, la valeur retournée par la fonction. La seule différence entre une fonction et toute autre valeur dans JS est que la fonction peut être exécutée ou appelée.

34. Comment implémenteriez-vous la méthode Array.prototype.map?


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
    }
}

La méthode map crée un nouveau tableau avec pour résultat d'appeler la fonction spécifiée pour chaque élément du tableau.

35. Comment implémenteriez-vous la méthode Array.prototype.filter?


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
    }
}

La méthode de filtrage crée un nouveau tableau avec tous les éléments qui ont réussi le test spécifié dans la fonction transmise.

36. Comment implémenteriez-vous la méthode Array.prototype.reduce?


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
    }
}

La méthode de réduction applique la fonction de réduction à chaque élément du tableau (de gauche à droite), en renvoyant une valeur résultante.

37. Qu'est-ce qu'un objet arguments?


Arguments est une collection d'arguments passés à une fonction. Il s'agit d'un objet de type tableau, il a la propriété length, nous pouvons accéder à une valeur spécifique en utilisant des arguments [i], mais il n'a pas les méthodes forEach, reduction, filter et map. Il vous permet de connaître le nombre de paramètres de fonction.

Vous pouvez convertir des arguments en tableau à l'aide de Array.prototype.slice:

Array.prototype.slice.call(arguments)

N'oubliez pas: dans les fonctions fléchées, l'objet arguments ne fonctionne pas.

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

four() // arguments is not defined

L'appel des quatre fonctions entraîne une erreur ReferenceError: arguments n'est pas définie. Ce problème peut être résolu en utilisant l'instruction rest:

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

Cela mettra automatiquement tous les paramètres dans un tableau.

38. Comment créer un objet qui n'a pas de prototype?


Cela peut être fait en utilisant 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. Pourquoi dans le code présenté la variable b devient-elle globale lorsque la fonction est appelée?



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

Cela se produit car l'opérateur d'affectation ("=") a une associativité droitière, c'est-à-dire attribue des valeurs de droite à gauche. Par conséquent, le code prend la forme suivante:

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

Tout d'abord, la valeur 0 est affectée à la variable "b", qui n'est pas déclarée. Le moteur JS le rend mondial. La valeur (0) retournée par b = 0 est alors affectée à la variable locale "a".

Ce problème peut être résolu en déclarant d'abord des variables locales, puis en leur affectant des valeurs:

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

40. Qu'est-ce que ECMAScript?


ECMAScript est une spécification, un langage de programmation de script standard, c'est la base de JS, donc toutes les modifications apportées à ECMAScript sont reflétées dans JS.

La dernière version de la spécification ECMA-262 peut être consultée ici .

41. Quelles nouveautés ES6 ou ECMAScript2015 ont-ils apporté à JS?


  • Fonctions fléchées
  • Des classes
  • Chaînes de modèle.
  • Littéraux d'objets améliorés
  • Déstructuration (Destruction d'objets).
  • Promesses (promesses).
  • Générateurs
  • Modules
  • Symbole.
  • Procurations
  • Ensembles.
  • Les options par défaut.
  • Reposez et répartissez les opérateurs.
  • Portée du bloc (mots clés «let» et «const»).

42. Quelle est la différence entre les mots clés «var», «let» et «const»?


Les variables déclarées à l'aide du mot clé var sont globales. Cela signifie qu'ils sont accessibles de n'importe où dans le code:

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

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

Le résultat du premier console.log ne sera pas défini, le second - 5. Nous avons accès à la variable «x» en raison de son émergence dans la portée globale. Le code de l'exemple ci-dessus est interprété comme suit:

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

Le résultat du premier console.log n'est pas défini, car les variables déclarées auxquelles aucune valeur n'est attribuée ne sont pas définies par défaut.

Les variables déclarées à l'aide des mots clés "let" et "const" ont une portée de bloc. Cela signifie qu'ils ne sont disponibles qu'à l'intérieur du bloc ({}):

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

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

L'appel de ces fonctions avec le faux paramètre entraînera une erreur ReferenceError, car les variables "x" et "y" ne sont pas accessibles en dehors du bloc et leurs valeurs ne sont pas renvoyées (ne pas apparaître).

La différence entre «let» et «const» est que dans le premier cas, nous pouvons changer la valeur de la variable, et dans le second - no (constant). Dans le même temps, nous pouvons changer la valeur de la propriété d'un objet déclaré à l'aide de const, mais pas la propriété elle-même (variable).

43. Que sont les fonctions fléchées (fonctions fléchées)?


La fonction flèche est une façon relativement nouvelle de créer des fonctions dans JS. Les fonctions fléchées sont plus rapides et ont une syntaxe plus lisible que les expressions fonctionnelles. Dans les fonctions fléchées, le mot "fonction" est omis:

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

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

Dans une expression fonctionnelle, nous utilisons le mot-clé return pour renvoyer une valeur. Dans la fonction flèche, nous ne le faisons pas, car les fonctions flèche renvoient implicitement des valeurs, à condition de renvoyer une seule expression ou valeur:

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

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

Nous pouvons également passer des paramètres aux fonctions fléchées. Si nous transmettons un paramètre, nous n'avons pas besoin de le mettre entre parenthèses:

const getArgs = () => arguments

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

Les fonctions fléchées n'ont pas accès à l'objet arguments. Par conséquent, l'appel de la première fonction entraînera une erreur. Pour obtenir les paramètres passés à la fonction, nous pouvons utiliser l'opérateur de repos.

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. Que sont les classes?


Les classes sont une façon relativement nouvelle d'écrire des fonctions constructeurs dans JS. C'est du sucre syntaxique pour les fonctions constructeurs. Les classes sont basées sur les mêmes prototypes et héritage de prototype:

// 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}`
    }
}

Substitutions de méthodes et héritage d'une autre classe:

// 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]'
    }
}

Comment s'initier à l'utilisation des 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. Que sont les littéraux modèles?


Les littéraux de modèle sont une façon relativement nouvelle de créer des chaînes dans JS. Les littéraux de modèle sont créés à l'aide de doubles backticks (``):

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

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

Dans les littéraux de modèle, nous n'avons pas besoin d'échapper aux guillemets simples.
// ES5
var lastWords = '\n'
    + ' I \n'
    + ' am \n'
    + 'Iron Man \n'

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

Dans ES6, nous n'avons pas besoin d'utiliser la séquence d'échappement "\ n" pour alimenter la ligne.

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

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

Dans ES6, nous n'avons pas besoin d'utiliser la concaténation de chaînes pour combiner du texte avec une variable: nous pouvons utiliser l'expression $ {expr} pour obtenir la valeur de la variable.

46. ​​Qu'est-ce que la destruction d'objets?


La déstructuration est un moyen relativement nouveau d'obtenir (récupérer) les valeurs d'un objet ou d'un tableau.

Disons que nous avons un objet comme celui-ci:

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

Auparavant, pour créer les propriétés d'un objet, nous avons créé des variables pour chaque propriété. C'était très ennuyeux et très ennuyeux:

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

L'utilisation de la déstructuration rend le code plus propre et prend moins de temps. La syntaxe de déstructuration est la suivante: nous mettons les propriétés d'objet que nous voulons recevoir entre crochets ({}), et si nous parlons d'un tableau, entre crochets ([]):

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

Pour modifier le nom de la variable, utilisez "propertyName: newName":

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

Pour affecter des valeurs par défaut aux variables, utilisez "propertyName = 'defaultValue'":

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

47. Que sont les modules?


Les modules vous permettent de combiner (utiliser) du code provenant de différents fichiers et nous évitent d'avoir à conserver tout le code dans un seul grand fichier. Avant l'apparition des modules dans JS, il existait deux systèmes de modules populaires pour la prise en charge du code:

  • CommonJS - Nodejs
  • AMD (AsyncronousModuleDefinition) - Navigateurs

La syntaxe des modules est très simple: nous utilisons l'importation pour importer des fonctionnalités ou des valeurs à partir d'un ou plusieurs fichiers, et exporter pour exporter.

Fonction d'exportation vers un autre fichier (nommé exportation):

// 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);
}

Importer des fonctionnalités dans un autre fichier:

// 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"  

Export par défaut:

// 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

Importation:

// 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))

Il s'agit de l'utilisation de base des modules. Je ne suis pas entré dans les détails, car mon post est déjà trop volumineux.

48. Qu'est-ce qu'un objet Set?


L'objet Set vous permet de stocker des valeurs uniques, des primitives et des références d'objet. Encore une fois: seules des valeurs uniques peuvent être ajoutées à Set. Il vérifie les valeurs qui y sont stockées à l'aide de l'algorithme SameZeroValue.

Une instance Set est créée à l'aide du constructeur Set. On peut aussi lui passer quelques valeurs lors de la création:

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

Nous pouvons ajouter des valeurs à Set en utilisant la méthode add. Puisque la méthode add est retournable, nous pouvons utiliser une chaîne d'appels:

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

Nous pouvons supprimer des valeurs de Set en utilisant la méthode delete:

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

Nous pouvons vérifier une propriété dans Set en utilisant la méthode has:

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

Pour obtenir la longueur de Set, utilisez la méthode de taille:

set2.size // 10

La méthode clear efface Set:

set2.clear() // 

Nous pouvons utiliser Set pour supprimer les valeurs en double dans un tableau:

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. Qu'est-ce qu'une fonction de rappel?


La fonction de rappel est une fonction dont l'appel est reporté pour le futur (se produit dans certaines conditions, par exemple, lorsqu'un événement se produit).

const btnAdd = document.getElementById('btnAdd')

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

Dans l'exemple, nous attendons un événement «click» sur un élément avec l'identifiant «btnAdd». En cliquant, la fonction clickCallback est appelée. La fonction de rappel ajoute des fonctionnalités aux données ou à l'événement. Les méthodes de réduction, de filtrage et de mappage reçoivent une fonction de rappel comme deuxième argument. Une bonne analogie avec le rappel est la situation suivante: vous appelez quelqu'un, il ne répond pas, vous lui laissez un message et attendez qu'il rappelle. Un appel ou un message est un événement ou des données, et un rappel est l'attente (anticipation) d'un appel de retour.

50. Quelles sont les promesses?


Les promesses sont une façon de travailler avec du code asynchrone dans JS. Ils renvoient le résultat d'une opération asynchrone. Des promesses ont été inventées pour résoudre le problème de ce que l'on appelle l'enfer des fonctions de rappel.

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

Les problèmes avec cette approche commencent lorsque nous devons ajouter une autre opération asynchrone à la première (à l'intérieur de la première), puis à une autre, etc. En conséquence, nous obtenons un code désordonné et illisible:

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

Et voici à quoi cela ressemble avec des promesses:

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

La promesse a quatre conditions:

  • L'attente est l'état initial d'une promesse. Le résultat de la promesse est inconnu car l'opération n'est pas terminée.
  • Terminé - Opération asynchrone terminée, il y a un résultat.
  • Rejeté - l'opération asynchrone a échoué, il y a une raison.
  • Terminé - terminé ou rejeté.

Le constructeur Promise accepte la résolution et le rejet en tant que paramètres. En résolution, le résultat de l'opération est enregistré, en rejet, la raison de l'échec de l'opération. Le résultat peut être traité dans la méthode .then, l'erreur peut être traitée dans la méthode .catch. La méthode .then renvoie également une promesse, nous pouvons donc utiliser une chaîne composée de plusieurs .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)
})

Nous pouvons créer une fonction d'assistance pour convertir une opération asynchrone de rappel en promesse. Cela fonctionnera comme util de 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))

Vous pouvez en savoir plus sur les promesses ici et ici .

51. Qu'est-ce que l'async / attente?


Async / Wait est une façon relativement nouvelle d'écrire du code asynchrone (non bloquant) dans JS. Ils sont enveloppés d'une promesse. Il rend le code plus lisible et plus propre que les fonctions de promesses et de rappel. Cependant, pour utiliser async / wait, vous devez bien connaître les promesses.

// 
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){
        //   
    }
}

N'oubliez pas: l'utilisation du mot-clé async avant qu'une fonction ne l'oblige à renvoyer une promesse:

const giveMeOne = async () = 1

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

Le mot clé wait ne peut être utilisé qu'à l'intérieur d'une fonction asynchrone. L'utilisation de l'attente dans une autre fonction entraînera une erreur. Attendre attend que l'expression se termine à droite pour renvoyer sa valeur avant d'exécuter la ligne de code suivante.

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

En savoir plus sur async / attendez ici et ici .

52. Quelle est la différence entre un opérateur d'épandage et un opérateur de repos?


Les instructions spread et rest ont la même syntaxe ("..."). La différence réside dans le fait qu'avec l'aide de la propagation, nous transférons ou répartissons les données du tableau vers d'autres données, et avec l'aide du repos, nous obtenons tous les paramètres de la fonction et les mettons dans le tableau (ou nous extrayons certains des paramètres).

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

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

Dans cet exemple, nous utilisons spread lors de l'appel de la fonction add avec les données du tableau nums. La valeur de la variable «a» sera 5, b = 6, somme = 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

Ici, nous appelons la fonction add avec un nombre quelconque d'arguments. Add renvoie la somme de ces arguments.

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

Dans cet exemple, nous utilisons rest pour placer un nombre quelconque de paramètres, à l'exception du premier, dans le tableau des autres.

53. Quels sont les paramètres par défaut?


Il s'agit d'une façon relativement nouvelle de définir les valeurs des variables par défaut.

// 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

Vous pouvez utiliser la déstructuration:

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]

On peut même utiliser les paramètres par défaut déclarés au même endroit:

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

54. Qu'est-ce qu'un wrapper d'objets (Wrapper Objects)?


La chaîne, le nombre et le booléen primitifs ont des propriétés et des méthodes, bien qu'ils ne soient pas des objets:

let name = 'marko'

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

Le nom est une chaîne (type primitif) qui n'a ni propriétés ni méthodes, mais lorsque nous appelons la méthode toUpperCase (), cela ne conduit pas à une erreur, mais à «MARKO».

La raison de ce comportement est que le nom est temporairement converti en objet. Chaque primitive, sauf null et non défini, a un objet wrapper. Ces objets sont String, Number, Boolean, Symbol et BigInt. Dans notre cas, le code prend la forme suivante:

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

Un objet temporaire est jeté à la fin du travail avec une propriété ou une méthode.

55. Quelle est la différence entre la contrainte implicite et la contrainte explicite?


La conversion implicite est un moyen de convertir une valeur en un autre type à notre insu (participation).

Supposons que nous ayons les éléments suivants:

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

Le résultat du premier console.log sera 16. Dans d'autres langues, cela entraînerait une erreur, mais dans JS 1, il est converti en chaîne et concaténé (attaché) à partir de 6. Nous n'avons rien fait, la conversion s'est produite automatiquement.

Le résultat du deuxième console.log sera 1. False a été converti en 0, vrai en 1. 0 + 1 = 1.

Le résultat du troisième console.log sera 12. La ligne 2 a été convertie en nombre avant de multiplier par 6. La

conversion explicite implique notre participation à conversion de la valeur dans un autre type:

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

Dans cet exemple, nous utilisons parseInt pour convertir la chaîne 6 en un nombre, puis additionner les deux nombres et obtenir 7.

56. Qu'est-ce que NaN? Comment vérifier si la valeur est NaN?


NaN ou Not A Number (pas un nombre) est la valeur obtenue à la suite de l'exécution d'une opération numérique sur une valeur non numérique:

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 a une méthode isNaN intégrée qui vous permet de vérifier si la valeur est NaN, mais elle se comporte assez étrangement:

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

Le résultat de tous console.log est vrai, malgré le fait qu'aucune des valeurs ne soit NaN.

ES6 recommande d'utiliser la méthode Number.isNaN pour vérifier si la valeur est NaN. On peut également écrire une fonction auxiliaire pour résoudre le problème de «l'inégalité NaN pour elle-même»:

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

57. Comment vérifier si une valeur est un tableau?


Pour ce faire, utilisez la méthode Array.isArray:

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

Si l'environnement dans lequel vous travaillez ne prend pas en charge cette méthode, vous pouvez utiliser le polyfichier suivant:

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

58. Comment vérifier qu'un nombre est pair, sans utiliser la division modulo ou la division avec le reste (opérateur "%")?


Pour résoudre ce problème, vous pouvez utiliser l'opérateur "&" (binaire et). L'opérateur & compare les opérandes en tant que valeurs binaires.

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

0 dans la notation binaire est 000
1 - ce qui est 001
2-010
3-011
4-100
5-101
6-110
7-111
, etc.



Console.log (5 & 1) renverra 1. Tout d'abord, l'opérateur & convertit les deux nombres en valeurs binaires, 5 tours en 101, 1 tours en 001. Ensuite, une comparaison au niveau du bit est effectuée:



Comparez 1 et 0, nous obtenons 0.
Comparez 0 et 0 , nous obtenons 0.
Comparez 1 et 1, nous obtenons 1.
Convertissez la valeur binaire en un entier, nous obtenons 1.

Si ces informations vous semblent trop compliquées, nous pouvons résoudre le problème en utilisant la fonction récursive:

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

59. Comment déterminer la présence d'une propriété dans un objet?


Il y a trois façons de procéder.

La première consiste à utiliser l'opérateur in:

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

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

La seconde consiste à utiliser la méthode hasOwnProperty:

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

La troisième est la notation d'index du tableau:

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

60. Qu'est-ce que AJAX?


AJAX ou Asyncronous JavaScript and XML est un ensemble de technologies interconnectées qui vous permettent de travailler avec des données en mode asynchrone. Cela signifie que nous pouvons envoyer des données au serveur et en recevoir des données sans recharger la page Web.

AJAX utilise les technologies suivantes:
HTML - structure de page Web.
CSS - styles de page Web.
JavaScript - comportement des pages et utilisation du DOM.
API XMLHttpRequest - envoi et réception de données du serveur.
PHP, Python, Nodejs - une sorte de langage serveur.

61. Comment créer un objet dans JS?


Littéral d'objet:

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

o.greeting // Hi, I'm Mark

Fonction constructeur:

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

Méthode Object.create:

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. Quelle est la différence entre les méthodes Object.freeze et Object.seal?


La différence est que lorsque vous utilisez la méthode Object.freeze, nous ne pouvons pas modifier ou modifier les propriétés de l'objet, et lorsque nous utilisons Object.seal nous avons une telle opportunité.

63. Quelle est la différence entre l'opérateur in et la méthode hasOwnProperty?


La différence est que l'opérateur "in" vérifie la présence d'une propriété non seulement dans l'objet lui-même, mais aussi dans ses prototypes, et la méthode hasOwnProperty - uniquement dans l'objet.

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. Quelles techniques de travail avec du code asynchrone dans JS connaissez-vous?


  • Rappels
  • Promesses (promesses).
  • Async / attendre.
  • Des bibliothèques comme async.js, blueprint, q, co.

65. Quelle est la différence entre une fonction normale et une expression fonctionnelle?


Disons que nous avons les éléments suivants:

hoistedFunc()
notHoistedFunc()

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

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

Un appel à notHoistedFunc entraînera une erreur, mais un appel à hoistedFunc ne le fera pas, car hoistedFunc «apparaît», atteint la portée globale, mais pas notHoistedFunc.

66. Comment appeler une fonction dans JS?


Dans JS, il existe 4 façons d'appeler une fonction. L'appel définit la valeur de ceci ou le "propriétaire" de la fonction.

Appelez en fonction. Si une fonction est appelée en tant que méthode, constructeur ou en utilisant les méthodes apply ou call, elle est appelée en tant que fonction. Le propriétaire d'une telle fonction est l'objet fenêtre:

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
})

Appelez comme méthode. Lorsqu'une fonction est une propriété d'un objet, nous l'appelons une méthode. Lorsqu'une méthode est appelée, l'objet this devient l'objet de cette méthode:

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

details.getName() // Marko,  this   details

Appelez en tant que constructeur. Lorsqu'une fonction est appelée à l'aide du mot-clé «new», nous appelons cette fonction un constructeur. Cela crée un objet vide, qui est la valeur de ceci:

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)

Un appel utilisant les méthodes apply ou call. Nous utilisons ces méthodes lorsque nous voulons déterminer explicitement la valeur de ceci ou le propriétaire d'une fonction:

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. Qu'est-ce que la mémorisation ou la mémorisation?


La mémorisation est la technique de création d'une fonction qui peut mémoriser des résultats ou des valeurs précédemment calculés. L'avantage de la mémorisation est que nous évitons de réexécuter une fonction avec les mêmes arguments. L'inconvénient est que nous sommes obligés d'allouer de la mémoire supplémentaire pour enregistrer les résultats.

68. Comment mettriez-vous en œuvre la fonction auxiliaire de mémorisation?


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') //  

Nous avons implémenté la fonction de mémorisation avec un argument. Faisons-en "multi-arguments":

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. Pourquoi typeof null renvoie un objet? Comment vérifier si une valeur est nulle?


typeof null == 'object' retournera toujours true pour des raisons historiques. Il a été proposé de corriger cette erreur en remplaçant typeof null = 'object' par typeof null = 'null', mais elle a été rejetée dans l'intérêt de maintenir la compatibilité descendante (une telle modification entraînerait un grand nombre d'erreurs).

Pour vérifier si la valeur est nulle, vous pouvez utiliser l'opérateur d'égalité stricte (===):

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

70. À quoi sert le «nouveau» mot clé?


Le mot-clé «new» est utilisé dans les fonctions constructeur pour créer un nouvel objet (une nouvelle instance de la classe).

Disons que nous avons un code comme celui-ci:

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

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

Le mot-clé "nouveau" fait 4 choses:

  1. Crée un objet vide.
  2. Lui lie la valeur this.
  3. Une fonction hérite de functionName.prototype.
  4. Renvoie ceci sauf indication contraire.

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


All Articles