70 Fragen zum Javascript-Interview

Guten Tag, Freunde!

Ich hoffe, dieser Artikel ist sowohl für Anfänger als auch für erfahrene Entwickler nützlich.

In Fragen, die mir schwieriger erschienen als andere, wird auf zusätzliche Literatur verwiesen.

Für die ausführlichen Kommentare wäre ich dankbar. Alle Kommentare werden bei der Bearbeitung des Artikels berücksichtigt.

So lass uns gehen.

70 Fragen zum Javascript-Interview


Fragen:
1. Was ist der Unterschied zwischen null und undefiniert?
2. Wofür wird der Operator && verwendet?
3. Wofür wird der Operator "||" verwendet?
4. Ist die Verwendung des unären Plus-Operators (+ Operator) der schnellste Weg, eine Zeichenfolge in eine Zahl umzuwandeln?
5. Was ist ein DOM?
6. Was ist Event Propogation?
7. Was ist Ereignisblasen?
8. Was ist Ereigniserfassung?
9. Was ist der Unterschied zwischen den Methoden event.preventDefault () und event.stopPropagation ()?
10. Wie lerne ich die Verwendung der event.preventDefault () -Methode kennen?
11. Warum führt obj.someprop.x zu einem Fehler?
12. Was ist ein Ereignisziel oder ein Zielelement (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. Welche Techniken zum Arbeiten mit asynchronem Code in JS kennen Sie?
65. Was ist der Unterschied zwischen einer normalen Funktion und einem funktionalen Ausdruck?
66. Wie rufe ich eine Funktion in JS auf?
67. Was ist Auswendiglernen oder Auswendiglernen?
68. Wie würden Sie die Hilfsfunktion des Auswendiglernen implementieren?
69. Warum gibt typeof null ein Objekt zurück? Wie überprüfe ich, ob ein Wert null ist?
70. Wofür wird das Schlüsselwort "neu" verwendet?

1. Was ist der Unterschied zwischen null und undefiniert?


Lassen Sie uns zunächst darüber sprechen, was sie gemeinsam haben.

Erstens gehören sie zu 7 JS "Primitiven" (primitiven Typen):

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

Zweitens sind sie falsche Werte, d.h. das Ergebnis der Konvertierung in einen Booleschen Wert mit Boolean () oder dem Operator "!!" ist falsch:

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

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

Okay, jetzt zu den Unterschieden.

undefiniert ist der Standardwert:
  • eine Variable, der kein Wert zugewiesen wurde, d.h. eine deklarierte, aber nicht initialisierte Variable;
  • eine Funktion, die nichts explizit zurückgibt, z. B. console.log (1);
  • nicht vorhandene Eigenschaft des Objekts.

In diesen Fällen setzt die JS-Engine den Wert auf undefiniert.

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 ist der "Wert ohne Wert". null ist der Wert, der der Variablen explizit zugewiesen wird. Im folgenden Beispiel erhalten wir null, wenn die Methode fs.readFile fehlerfrei funktioniert:

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

Beim Vergleich von null und undefiniert erhalten wir true, wenn der Operator "==" verwendet wird, und false, wenn der Operator "===" verwendet wird. Informationen dazu finden Sie weiter unten.

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

2. Wofür wird der Operator && verwendet?


Der Operator && (logisch und) findet und gibt den ersten falschen Wert oder den letzten Operanden zurück, wenn alle Werte wahr sind. Es wird ein Kurzschluss verwendet, um unnötige Kosten zu vermeiden:

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

Mit der if-Anweisung:

const router: Router = Router()

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

Gleiches gilt für den Operator &&:

const router: Router = Router()

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

3. Wofür wird der Operator "||" verwendet?


Der Operator "||" (boolean oder) findet und gibt den ersten wahren Wert zurück. Es wird auch ein Kurzschluss verwendet. Dieser Operator wurde verwendet, um Standardparameter in Funktionen zuzuweisen, bevor die Standardparameter in ES6 standardisiert wurden.

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

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

logName() // Mark

4. Ist die Verwendung des unären Plus-Operators (+ Operator) der schnellste Weg, eine Zeichenfolge in eine Zahl umzuwandeln?


Laut MDN ist der Operator + in der Tat der schnellste Weg, eine Zeichenfolge in eine Zahl umzuwandeln, da er keine Operationen für einen Wert ausführt, der eine Zahl ist.

5. Was ist ein DOM?


Das DOM oder Document Object Model ist eine Anwendungsprogrammierschnittstelle (API) für die Arbeit mit HTML- und XML-Dokumenten. Wenn der Browser das HTML-Dokument zum ersten Mal liest („analysiert“), bildet er ein großes Objekt, ein wirklich großes Objekt, das auf dem Dokument basiert - das DOM. Das DOM ist eine Baumstruktur (Dokumentbaum). Das DOM wird verwendet, um die Struktur des DOM selbst oder seiner einzelnen Elemente und Knoten zu interagieren und zu ändern.

Nehmen wir an, wir haben diesen HTML-Code:

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

Das DOM dieses HTML sieht folgendermaßen aus:



In JS wird das DOM durch ein Dokumentobjekt dargestellt. Das Document-Objekt verfügt über eine Vielzahl von Methoden zum Arbeiten mit Elementen, deren Erstellung, Änderung, Löschung usw.

6. Was ist Ereignisausbreitung?


Wenn ein Ereignis in einem DOM-Element auftritt, tritt es tatsächlich nicht nur darin auf. Das Ereignis "propagiert" vom Window-Objekt zu dem Element, das es aufgerufen hat (event.target). In diesem Fall durchdringt (beeinflusst) das Ereignis nacheinander alle Vorfahren des Zielelements. Eine Ereignisausbreitung besteht aus drei Stufen oder Phasen:
  1. Eintauchphase (Erfassung, Abfangen) - Ein Ereignis tritt im Fensterobjekt auf und steigt über alle seine Vorfahren zum Ereignisziel ab.
  2. Die Zielphase ist, wenn das Ereignis das Zielelement erreicht.
  3. Aufsteigende Phase - Ein Ereignis steigt aus event.target auf, durchläuft nacheinander alle seine Vorfahren und erreicht das Window-Objekt.



Lesen Sie hier und hier mehr über die Verteilung von Veranstaltungen .

7. Was ist ein Ereignis-Popup?


Wenn ein Ereignis in einem DOM-Element auftritt, betrifft es nicht nur dieses Element. Ein Ereignis „erscheint“ (wie eine Luftblase im Wasser), geht von dem Element, das das Ereignis verursacht hat (event.target), zu seinem übergeordneten Element und steigt dann noch höher zum übergeordneten Element des übergeordneten Elements des Elements, bis es das Fensterobjekt erreicht.

Nehmen wir an, wir haben dieses Markup:

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

Und so ein 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')
    })
})

Die addEventListener-Methode verfügt über einen dritten optionalen Parameter - useCapture. Wenn der Wert false ist (Standardeinstellung), beginnt das Ereignis mit der Aufstiegsphase. Wenn sein Wert wahr ist, beginnt das Ereignis mit der Eintauchphase (für die "Zuhörer" von Ereignissen, die an das Ziel des Ereignisses angehängt sind, befindet sich das Ereignis in der Zielphase und nicht in der Eintauch- oder Aufstiegsphase. Ereignisse in der Zielphase werden von allen Zuhörern des Elements in der Reihenfolge ausgelöst in dem sie unabhängig vom Parameter useCapture registriert wurden - ca. Wenn wir auf das untergeordnete Element klicken, wird in der Konsole Folgendes angezeigt: untergeordnetes Element, übergeordnetes Element, Großelternteil, HTML, Dokument, Fenster. Hier ist, was ein Ereignis-Popup ist.

8. Was ist ein Immersionsereignis?


Wenn ein Ereignis in einem DOM-Element auftritt, tritt es nicht nur darin auf. In der Immersionsphase steigt das Ereignis durch alle seine Vorfahren vom Fensterobjekt zum Ereignisziel ab.

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

Die addEventListener-Methode verfügt über einen dritten optionalen Parameter - useCapture. Wenn der Wert false ist (Standardeinstellung), beginnt das Ereignis mit der Aufstiegsphase. Wenn sein Wert wahr ist, beginnt das Ereignis mit der Tauchphase. Wenn wir auf das untergeordnete Element klicken, wird in der Konsole Folgendes angezeigt: Fenster, Dokument, HTML, Großeltern, Eltern, Kind. Dies ist das Eintauchen des Ereignisses.

9. Was ist der Unterschied zwischen den Methoden event.preventDefault () und event.stopPropagation ()?


Die Methode event.preventDefault () deaktiviert das Standardverhalten eines Elements. Wenn Sie diese Methode im Formularelement verwenden, wird das Senden des Formulars verhindert. Wenn Sie es im Kontextmenü verwenden, wird das Kontextmenü deaktiviert (diese Methode wird häufig im Keydown verwendet, um die Tastatur neu zu definieren, z. B. beim Erstellen eines Musik- / Videoplayers oder eines Texteditors - ca. Die Methode event.stopPropagation () deaktiviert die Ereignisausbreitung (Aufstieg oder Eintauchen).

10. Wie lerne ich die Verwendung der event.preventDefault () -Methode kennen?


Zu diesem Zweck können wir die Eigenschaft event.defaulPrevented verwenden, die einen Booleschen Wert zurückgibt, der als Indikator für die Anwendung auf das Element der Methode event.preventDefault dient.

11. Warum führt obj.someprop.x zu einem Fehler?



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

Die Antwort liegt auf der Hand: Wir versuchen, auf die undefinierte Eigenschaft x der Eigenschaft someprop zuzugreifen. obj .__ proto __.__ proto = null, daher wird undefined zurückgegeben, und undefined hat nicht die x-Eigenschaft.

12. Was ist ein Ereignisziel oder ein Zielelement (event.target)?


In einfachen Worten ist event.target das Element, in dem das Ereignis auftritt, oder das Element, das das Ereignis ausgelöst hat.

Wir haben das folgende 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>

Und so ein einfacher JS:

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

Wir haben dem äußeren Div einen „Zuhörer“ hinzugefügt. Wenn wir jedoch auf die Schaltfläche klicken, erhalten wir das Layout dieser Schaltfläche in der Konsole. Dies lässt den Schluss zu, dass das Element, das das Ereignis verursacht hat, die Schaltfläche selbst ist und nicht die externen oder internen Divs.

13. Was ist der aktuelle Zweck des Ereignisses (event.currentTarget)?


Event.currentTarget ist das Element, an das der Ereignis-Listener angehängt ist.

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

Und ein leicht modifizierter JS:

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

Wir haben den Hörer an die äußere Div angeschlossen. Wo immer wir klicken, sei es eine Schaltfläche oder eine der internen Divs, in der Konsole erhalten wir immer das Layout der externen Divs. Dies lässt den Schluss zu, dass event.currentTarget das Element ist, an das der Ereignis-Listener angehängt ist.

14. Was ist der Unterschied zwischen den Operatoren "==" und "==="?


Der Unterschied zwischen dem Operator == (abstrakte oder nicht strenge Gleichheit) und dem Operator === (strikte Gleichheit) besteht darin, dass der erste die Werte vergleicht, nachdem sie konvertiert oder in einen Typ umgewandelt wurden (Coersion), und der zweite - ohne eine solche Konvertierung .

Lassen Sie uns tiefer graben. Und zuerst sprechen wir über die Transformation.

Eine Konvertierung ist ein Prozess, bei dem ein Wert in einen anderen Typ umgewandelt wird, oder vielmehr ein Prozess, bei dem die verglichenen Werte in einen Typ umgewandelt werden. Beim Vergleich des Operators "==" wird der sogenannte implizite Vergleich erzeugt. Der Operator "==" führt einige Operationen aus, bevor er zwei Werte vergleicht.

Angenommen, wir vergleichen x und y.

Der Algorithmus ist wie folgt:

  1. Wenn x und y vom gleichen Typ sind, wird der Vergleich mit dem Operator "===" durchgeführt.
  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.

Denken Sie daran: Um ein Objekt in ein "Grundelement" umzuwandeln, verwendet die toPrimitive-Methode zuerst die valueOf-Methode und dann die toString-Methode.

Beispiele:



Alle Beispiele geben true zurück.

Das erste Beispiel ist die erste Bedingung des Algorithmus.
Das zweite Beispiel ist die vierte Bedingung.
Der dritte ist der zweite.
Der vierte ist der siebte.
Fünfter - Achter.
Und der letzte ist der zehnte.



Wenn wir den Operator "===" verwenden, geben alle Beispiele außer dem ersten false zurück, da die Werte in diesen Beispielen unterschiedlichen Typs sind.

15. Warum ist das Ergebnis des Vergleichs zweier ähnlicher Objekte falsch?


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

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

In JS werden Objekte und Grundelemente unterschiedlich verglichen. Primitive werden nach Wert verglichen. Objekte - nach Referenz oder Adresse im Speicher, in dem die Variable gespeichert ist. Aus diesem Grund gibt das erste console.log false und das zweite true zurück. Die Variablen "a" und "c" beziehen sich auf dasselbe Objekt, während sich die Variablen "a" und "b" auf verschiedene Objekte mit denselben Eigenschaften und Werten beziehen.

16. Wofür wird der Operator "!!" verwendet?


Der Betreiber "!!" (doppelte Negation) führt den Wert rechts von ihm zu einem logischen Wert.

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. Wie schreibe ich mehrere Ausdrücke in eine Zeile?


Hierfür können wir den Operator "," (Komma) verwenden. Dieser Operator "bewegt" sich von links nach rechts und gibt den Wert des letzten Ausdrucks oder Operanden zurück.

let x = 5

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

function addFive(num) {
    return num + 5
}

Wenn wir den Wert von x auf die Konsole drucken, erhalten wir 27. Zuerst erhöhen wir den Wert von x um eins (x = 6). Dann rufen wir die Funktion addFive () mit Parameter 6 auf, zu der wir 5 hinzufügen (x = 11). Danach multiplizieren wir den Wert von x mit 2 (x = 22). Dann subtrahiere 5 (x = 17). Und schließlich addieren Sie 10 (x = 27).

18. Was ist Heben?


Lift ist ein Begriff, der den Aufstieg einer Variablen oder Funktion in einem globalen oder funktionalen Bereich beschreibt.

Um zu verstehen, was Heben ist, müssen Sie den Ausführungskontext verstehen.

Der Ausführungskontext ist die Umgebung, in der der Code ausgeführt wird. Der Ausführungskontext besteht aus zwei Phasen - Kompilierung und Ausführung selbst.

Zusammenstellung. In dieser Phase werden funktionale Ausdrücke und Variablen, die mit dem Schlüsselwort "var" mit dem Wert undefined deklariert wurden, ganz oben im globalen (oder funktionalen) Bereich angezeigt (als würden wir an den Anfang unseres Codes gehen. Dies erklärt, warum wir Funktionen vor ihnen aufrufen können Ankündigungen - ca.

Performance. In dieser Phase werden Variablen Werte zugewiesen und Funktionen (oder Methoden von Objekten) aufgerufen oder ausgeführt.

Denken Sie daran: Es werden nur funktionale Ausdrücke und Variablen ausgelöst, die mit dem Schlüsselwort "var" deklariert wurden. Gewöhnliche Funktionen und Pfeilfunktionen sowie Variablen, die mit den Schlüsselwörtern "let" und "const" deklariert wurden, werden nicht ausgelöst.

Angenommen, wir haben folgenden Code:

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

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

var y

Wir werden undefiniert, 1 und 'Hallo Mark!'.

So sieht die Kompilierungsphase aus:

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

var y //  undefined

//    

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

Nach Abschluss der Kompilierungsphase beginnt die Ausführungsphase, wenn den Variablen Werte zugewiesen und Funktionen aufgerufen werden.

Mehr zum Heben finden Sie hier .

19. Was ist ein Anwendungsbereich?


Ein Bereich ist ein Ort, an dem (oder von wo aus) wir Zugriff auf Variablen oder Funktionen haben. JS Wir haben drei Arten von Bereichen: global, funktional und block (ES6).

Globaler Bereich - Variablen und Funktionen, die im globalen Namespace deklariert sind, haben einen globalen Bereich und sind von überall im Code zugänglich.

//   
var g = 'global'

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

Funktionsumfang (Funktionsumfang) - Variablen, Funktionen und Parameter, die innerhalb einer Funktion deklariert sind, sind nur innerhalb dieser Funktion verfügbar.

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

Blockbereich - Variablen (deklariert mit den Schlüsselwörtern "let" und "const") innerhalb des Blocks ({}) sind nur innerhalb des Blocks verfügbar.

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

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

Ein Bereich ist auch ein Satz von Regeln, nach denen eine Variable durchsucht wird. Wenn die Variable im aktuellen Bereich nicht vorhanden ist, wird ihre Suche in der externen Sichtbarkeit des aktuellen Bereichs höher ausgeführt. Wenn der externe Bereich keine Variable enthält, wird die Suche bis zum globalen Bereich fortgesetzt. Wenn eine Variable im globalen Bereich gefunden wird, wird die Suche gestoppt. Andernfalls wird eine Ausnahme ausgelöst. Die Suche wird von denjenigen durchgeführt, die den aktuellen Sichtbarkeitsbereichen am nächsten liegen, und endet mit dem Auffinden der Variablen. Dies wird als Scope Chain bezeichnet.

//   
//    ->    ->   

//   
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. Was ist ein Verschluss (Closures)?


Dies ist wahrscheinlich die schwierigste Frage aus der Liste. Ich werde versuchen zu erklären, wie ich Schließung verstehe.

In der Tat ist das Schließen die Fähigkeit einer Funktion, Verknüpfungen zu Variablen und Parametern zu erstellen, die sich im aktuellen Bereich, im Bereich der übergeordneten Funktion, im Bereich des übergeordneten Bereichs der übergeordneten Funktion usw. zum globalen Bereich befinden, wobei die Kette der Bereiche zum Zeitpunkt der Erstellung verwendet wird. In der Regel wird der Umfang beim Erstellen einer Funktion festgelegt.

Beispiele sind eine gute Möglichkeit, den Abschluss zu erklären:

//   
var globalVar = 'abc'

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

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

Wenn wir in diesem Beispiel eine Funktion deklarieren, ist der globale Bereich Teil des Abschlusses.



Die Variable „globalVar“ spielt im Bild keine Rolle, da sich ihr Wert abhängig davon ändern kann, wo und wann die Funktion aufgerufen wird. Im obigen Beispiel hat globalVar jedoch den Wert "abc".

Jetzt ist das Beispiel komplizierter:

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



Das Ergebnis ist "erraten äußere innere". Die Erklärung lautet wie folgt: Wenn wir die OuterFunc-Funktion aufrufen und die Variable "x" auf den von der InnerFunc-Funktion zurückgegebenen Wert setzen, entspricht der Parameter "OuterParam" "Outer". Trotz der Tatsache, dass wir die Variable "OuterVar" "Outer-2" zugewiesen haben, geschah dies nach dem Aufruf der Funktion "OuterFunc", die es "geschafft" hat, den Wert der Variablen "OuterVar" in der Bereichskette zu finden. Dieser Wert war "Outer". Wenn wir "x" aufrufen, was sich auf innerFunc bezieht, ist der Wert von "innerParam" "inner", da wir diesen Wert als Parameter übergeben, wenn wir "x" aufrufen. globalVar hat den Wert "rate", da wir ihm diesen Wert zugewiesen haben, bevor wir "x" aufgerufen haben.

Ein Beispiel für ein Missverständnis einer Schaltung.

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
}

Dieser Code funktioniert nicht wie erwartet. Durch das Deklarieren einer Variablen mit dem Schlüsselwort var wird diese Variable global. Nach dem Hinzufügen von Funktionen zum Array arrFunc wird der Wert der globalen Variablen "i" zu "5". Wenn wir die Funktion aufrufen, gibt sie daher den Wert der globalen Variablen "i" zurück. Ein Abschluss speichert einen Verweis auf eine Variable, nicht ihren Wert zum Zeitpunkt der Erstellung. Dieses Problem kann durch Verwendung von IIFE oder durch Deklarieren einer Variablen mit dem Schlüsselwort "let" gelöst werden.

Lesen Sie hier und hier mehr über die Schließung .

21. Welche Werte in JS sind falsch?


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

False sind Werte, deren Konvertierung in einen Booleschen Wert false ist.

22. Wie überprüfe ich, ob ein Wert falsch ist?


Verwenden Sie die Boolesche Funktion oder den Operator "!!" (zweimal nein).

23. Wofür wird die strikte Richtlinie verwendet?


"Use strict" ist eine ES5-Direktive, die den gesamten Code oder den Code einer einzelnen Funktion zur Ausführung im strengen Modus zwingt. Der strikte Modus führt einige Einschränkungen beim Schreiben von Code ein, wodurch Fehler in den frühen Stadien vermieden werden.

Hier sind die Einschränkungen des strengen Modus.

Sie können keine Werte zuweisen oder auf nicht deklarierte Variablen zugreifen:

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

Es ist verboten, schreibgeschützten oder schreibgeschützten Variablen globale Werte zuzuweisen:

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

Sie können die Eigenschaft "nicht löschbar" eines Objekts nicht löschen:

'use strict'
const obj = {}

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

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

Das Duplizieren von Parametern ist verboten:

'use strict'

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

Mit der Funktion eval können Sie keine Funktionen erstellen:

'use strict'

eval('var x = 1')

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

Der Standardwert hierfür ist undefiniert:

'use strict'

function showMeThis() {
    return this
}

showMeThis() // undefined

… usw.

24. Was bedeutet das?


Dies bezieht sich normalerweise auf den Wert des Objekts, das gerade die Funktion ausführt oder aufruft. "Im Moment" bedeutet, dass der Wert davon abhängig vom Ausführungskontext variiert, in dem wir dies verwenden.

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

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

In diesem Fall gibt die Methode getName this.name zurück. Dies bezieht sich auf carDetails, das Objekt, in dem getName ausgeführt wird, und dessen "Eigentümer".

Fügen Sie nach console.log drei Zeilen hinzu:

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

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

Das zweite console.log produziert einen Ford Ranger, und das ist komisch. Der Grund für dieses Verhalten ist, dass der "Eigentümer" von getCarName das Fensterobjekt ist. Mit dem Schlüsselwort var im globalen Bereich deklarierte Variablen werden in die Eigenschaften des Fensterobjekts geschrieben. Dies bezieht sich im globalen Bereich auf das Fensterobjekt (es sei denn, es handelt sich um einen strengen Modus).

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

In diesem Beispiel beziehen sich dieses und das Fenster auf dasselbe Objekt.

Eine Möglichkeit, dieses Problem zu lösen, besteht darin, den Aufruf zu verwenden oder Methoden anzuwenden:

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

Rufen Sie auf und wenden Sie als erstes Argument ein Objekt an, dessen Wert dies innerhalb der Funktion ist.

In IIFE sind Funktionen, die im globalen Bereich erstellt werden, anonyme Funktionen und interne Funktionen der Methoden eines Objekts. Der Standardwert hierfür ist das Fensterobjekt.

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

Es gibt zwei Möglichkeiten, um Marko Polo zu bekommen.

Erstens können wir den Wert davon in einer Variablen speichern:

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

Zweitens können wir die Pfeilfunktion verwenden:

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

Pfeilfunktionen haben diesen Eigenwert nicht. Sie kopieren die Bedeutung davon aus der externen lexikalischen Umgebung.

25. Was ist ein Prototyp eines Objekts?


Kurz gesagt, ein Prototyp ist ein Plan (Diagramm oder Projekt) eines Objekts. Es wird als Fallback für die in diesem Objekt vorhandenen Eigenschaften und Methoden verwendet. Dies ist auch eine der Möglichkeiten, Eigenschaften und Funktionen zwischen Objekten auszutauschen. Dies ist das Grundkonzept der Prototypvererbung in JS.

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

Obwohl das Objekt "o" nicht über die Eigenschaft toString verfügt, führt der Zugriff auf diese Eigenschaft nicht zu einem Fehler. Befindet sich eine bestimmte Eigenschaft nicht im Objekt, wird ihre Suche zuerst im Prototyp des Objekts, dann im Prototyp des Prototyps des Objekts usw. ausgeführt, bis die Eigenschaft gefunden wird. Dies wird als Prototypkette bezeichnet. Am Anfang der Prototypenkette steht Object.prototype.

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

Lesen Sie hier und hier mehr über Prototypen und Vererbung .

26. Was ist IIFE?


IIFE oder sofort aufgerufene Funktion Ausdruck ist eine Funktion, die unmittelbar nach der Erstellung oder Deklaration aufgerufen oder ausgeführt wird. Um IIFE zu erstellen, müssen Sie die Funktion in Klammern (den Gruppierungsoperator) einschließen, in einen Ausdruck umwandeln und dann mit anderen Klammern aufrufen. Es sieht so aus: (function () {}) ().

(function( ) { }( ))

(function( ) { })( )

(function named(params) { })( )

(( ) => { })

(function(global) { })(window)

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

Alle diese Beispiele sind gültig. Das vorletzte Beispiel zeigt, dass wir Parameter an IIFE übergeben können. Das letzte Beispiel zeigt, dass wir das Ergebnis von IIFE in einer Variablen speichern können.

Die beste Verwendung von IIFE besteht darin, Konfigurationsfunktionen für die Initialisierung auszuführen und Namenskonflikte mit anderen Variablen im globalen Bereich (Verschmutzung des globalen Namespace) zu verhindern. Wir geben ein Beispiel.

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

Wir haben einen Link zur Bibliothek somelibrary.js, die einige globale Funktionen bereitstellt, die wir in unserem Code verwenden können. In dieser Bibliothek gibt es jedoch zwei Methoden, createGraph und drawGraph, die wir nicht verwenden, da sie Fehler enthalten. Und wir wollen diese Funktionen selbst implementieren.

Eine Möglichkeit, dieses Problem zu lösen, besteht darin, die Struktur unserer Skripte zu ändern:

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

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

Daher definieren wir die von der Bibliothek bereitgestellten Methoden neu.

Der zweite Weg ist die Änderung der Namen unserer Funktionen:

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

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

Der dritte Weg ist die Verwendung von IIFE:

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

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

In diesem Beispiel erstellen wir eine Dienstprogrammvariable, die das IIFE-Ergebnis enthält und ein Objekt zurückgibt, das die Methoden createGraph und drawGraph enthält.

Hier ist ein weiteres Problem, das mit IIFE gelöst werden kann:

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

Angenommen, wir haben ein ul-Element mit einer Listengruppenklasse, die 5 untergeordnete Elemente li enthält. Und wir möchten den Wert "i" in der Konsole anzeigen, wenn wir auf ein separates "li" klicken. Stattdessen zeigt die Konsole jedoch immer 5 an. Der Fehler ist der gesamte Fehler.

Eine Lösung ist 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)
}

Der Grund, warum dieser Code wie beabsichtigt funktioniert, ist, dass IIFE bei jeder Iteration einen neuen Bereich erstellt und wir den Wert "i" in currentIndex schreiben.

27. Wofür wird die Function.prototype.apply-Methode verwendet?


Mit Apply wird ein bestimmtes Objekt an diesen Wert der aufgerufenen Funktion gebunden.

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

function getMessage() {
    return this.message
}

getMessage.apply(details) // Hello World!

Diese Methode ähnelt Function.prototype.call. Der einzige Unterschied besteht darin, dass in apply die Argumente als Array übergeben werden.

const person = {
    name: 'Marko Polo'
}

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

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

28. Wofür wird die Methode function.prototype.call verwendet?


Call wird verwendet, um ein bestimmtes Objekt an den Wert dieser aufgerufenen Funktion zu binden.

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

function getMessage() {
    return this.message;
}

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

Diese Methode ähnelt Function.prototype.apply. Der Unterschied besteht darin, dass beim Aufruf Argumente durch Kommas getrennt übergeben werden.

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

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

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

29. Was ist der Unterschied zwischen Aufruf- und Anwendungsmethoden?


Der Unterschied zwischen call und apply besteht darin, wie wir Argumente in der aufgerufenen Funktion übergeben. In apply werden die Argumente als Array übergeben, in call, durch Kommas getrennt.

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. Wofür wird die Methode function.prototype.bind verwendet?


Bind gibt eine neue Funktion zurück, deren Wert das als erster Parameter angegebene Objekt ist. Rufen Sie im Gegensatz zum Binden die Funktion auf und rufen Sie sie sofort auf.

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. Was ist funktionale Programmierung und welche Funktionen von JS ermöglichen es uns, darüber als funktionale Programmiersprache zu sprechen?


Funktionale Programmierung ist ein deklaratives Programmierkonzept oder ein Beispiel (Muster) dafür, wie Anwendungen erstellt werden und wie Funktionen verwendet werden, die Ausdrücke enthalten, die Werte berechnen, ohne die an sie übergebenen Argumente zu ändern.

Das Array-Objekt enthält die Zuordnungs-, Filter- und Reduzierungsmethoden, die aufgrund ihrer Nützlichkeit und auch, weil sie das Array nicht ändern, die diese Funktionen „sauber“ machen, die bekanntesten Funktionen in der Welt der funktionalen Programmierung sind. JS hat auch einen Abschluss und Funktionen höherer Ordnung, die Merkmale einer funktionalen Programmiersprache sind.

Die Map-Methode gibt ein neues Array mit Rückrufergebnissen für jedes Element des Arrays zurück:

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

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

Die Filtermethode erstellt ein neues Array mit allen Elementen, die die im Rückruf angegebene Bedingung erfüllen:

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

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

Die Reduktionsmethode führt einmalig einen Rückruf für jedes Element des Arrays aus, mit Ausnahme von Hohlräumen, wobei vier Argumente verwendet werden: der Anfangswert (oder der Wert aus dem vorherigen Rückruf), der Wert des aktuellen Elements, der aktuelle Index und das iterierte Array:

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

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

32. Was sind Funktionen höherer Ordnung?


Eine Funktion höherer Ordnung ist eine Funktion, die eine andere Funktion zurückgibt oder eine andere Funktion als Argument akzeptiert.

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

33. Warum werden Funktionen in JS als erstklassige Objekte bezeichnet?


Funktionen werden als erstklassige Objekte bezeichnet, da sie wie jeder andere Wert in JS verarbeitet werden. Sie können Variablen zugewiesen werden, eine Eigenschaft eines Objekts (einer Methode), ein Element eines Arrays, ein Argument für eine andere Funktion und der von der Funktion zurückgegebene Wert sein. Der einzige Unterschied zwischen einer Funktion und einem anderen Wert in JS besteht darin, dass die Funktion ausgeführt oder aufgerufen werden kann.

34. Wie würden Sie die Array.prototype.map-Methode implementieren?


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

Die Map-Methode erstellt ein neues Array mit dem Ergebnis des Aufrufs der angegebenen Funktion für jedes Element des Arrays.

35. Wie würden Sie die Array.prototype.filter-Methode implementieren?


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

Die Filtermethode erstellt ein neues Array mit allen Elementen, die den in der übergebenen Funktion angegebenen Test bestanden haben.

36. Wie würden Sie die Array.prototype.reduce-Methode implementieren?


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

Die Reduktionsmethode wendet die Reduzierungsfunktion auf jedes Element des Arrays an (von links nach rechts) und gibt einen resultierenden Wert zurück.

37. Was ist ein Argumentobjekt?


Argumente ist eine Sammlung von Argumenten, die an eine Funktion übergeben werden. Dies ist ein Array-ähnliches Objekt, es hat die Eigenschaft length, wir können mit Argumenten [i] auf einen bestimmten Wert zugreifen, aber es verfügt nicht über die Methoden forEach, redu, filter und map. Hier können Sie die Anzahl der Funktionsparameter ermitteln.

Sie können Argumente mit Array.prototype.slice in ein Array konvertieren:

Array.prototype.slice.call(arguments)

Denken Sie daran: In Pfeilfunktionen funktioniert das Argumentobjekt nicht.

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

four() // arguments is not defined

Das Aufrufen der vier Funktionen führt zu einem ReferenceError: Argumente ist kein definierter Fehler. Dieses Problem kann mit der rest-Anweisung gelöst werden:

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

Dadurch werden automatisch alle Parameter in ein Array eingefügt.

38. Wie erstelle ich ein Objekt ohne Prototyp?


Dies kann mit Object.create erfolgen:

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. Warum wird im dargestellten Code die Variable b global, wenn die Funktion aufgerufen wird?



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

Dies geschieht, weil der Zuweisungsoperator ("=") eine rechtshändige Assoziativität aufweist, d. H. weist Werte von rechts nach links zu. Daher hat der Code die folgende Form:

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

Zunächst wird der Variablen "b" der Wert 0 zugewiesen, der nicht deklariert ist. Die JS-Engine macht es global. Der von b = 0 zurückgegebene Wert (0) wird dann der lokalen Variablen "a" zugewiesen.

Dieses Problem kann gelöst werden, indem zuerst lokale Variablen deklariert und ihnen dann Werte zugewiesen werden:

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

40. Was ist ECMAScript?


ECMAScript ist eine Spezifikation, eine Standard-Programmiersprache für Skripte. Sie ist die Basis von JS, sodass alle Änderungen an ECMAScript in JS berücksichtigt werden.

Die neueste Version der ECMA-262-Spezifikation kann hier eingesehen werden .

41. Welche neuen Dinge brachte ES6 oder ECMAScript2015 zu JS?


  • Pfeilfunktionen
  • Klassen
  • Template Strings.
  • Erweiterte Objektliterale
  • Destrukturierung (Objektzerstörung).
  • Versprechen Versprechen).
  • Generatoren
  • Module
  • Symbol.
  • Proxies
  • Sets.
  • Die Standardoptionen.
  • Ruhe- und Verbreitungsoperatoren.
  • Blockbereich (Schlüsselwörter "let" und "const").

42. Was ist der Unterschied zwischen den Schlüsselwörtern "var", "let" und "const"?


Mit dem Schlüsselwort var deklarierte Variablen sind global. Dies bedeutet, dass sie von überall im Code zugänglich sind:

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

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

Das Ergebnis des ersten console.log ist undefiniert, das zweite - 5. Wir haben Zugriff auf die Variable "x", da sie in den globalen Bereich aufgenommen wird. Der Code aus dem obigen Beispiel wird wie folgt interpretiert:

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

Das Ergebnis der ersten console.log ist undefiniert, da deklarierte Variablen, denen kein Wert zugewiesen wurde, standardmäßig nicht definiert sind.

Variablen, die mit den Schlüsselwörtern "let" und "const" deklariert wurden, haben einen Blockbereich. Dies bedeutet, dass sie nur innerhalb des Blocks ({}) verfügbar sind:

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

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

Das Aufrufen dieser Funktionen mit dem Parameter false führt zu einem ReferenceError-Fehler, da auf die Variablen "x" und "y" außerhalb des Blocks nicht zugegriffen werden kann und ihre Werte nicht zurückgegeben werden (nicht auftauchen).

Der Unterschied zwischen "let" und "const" besteht darin, dass wir im ersten Fall den Wert der Variablen ändern können und im zweiten - no (Konstante). Gleichzeitig können wir den Wert der Eigenschaft eines mit const deklarierten Objekts ändern, nicht jedoch die Eigenschaft selbst (Variable).

43. Was sind Pfeilfunktionen (Pfeilfunktionen)?


Die Pfeilfunktion ist eine relativ neue Methode zum Erstellen von Funktionen in JS. Pfeilfunktionen sind schneller und haben eine besser lesbare Syntax als funktionale Ausdrücke. In Pfeilfunktionen wird das Wort "Funktion" weggelassen:

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

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

In einem funktionalen Ausdruck verwenden wir das Schlüsselwort return, um einen Wert zurückzugeben. In der Pfeilfunktion tun wir dies nicht, da Pfeilfunktionen implizit Werte zurückgeben, vorausgesetzt, wir geben einen einzelnen Ausdruck oder Wert zurück:

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

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

Wir können auch Parameter an Pfeilfunktionen übergeben. Wenn wir einen Parameter übergeben, müssen wir ihn nicht in Klammern setzen:

const getArgs = () => arguments

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

Pfeilfunktionen haben keinen Zugriff auf das Argumentobjekt. Daher führt der Aufruf der ersten Funktion zu einem Fehler. Um die Parameter an die Funktion zu übergeben, können wir den Rest-Operator verwenden.

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. Was sind Klassen?


Klassen sind eine relativ neue Art, Konstruktorfunktionen in JS zu schreiben. Dies ist syntaktischer Zucker für Konstruktorfunktionen. Klassen basieren auf denselben Prototypen und derselben Prototypenvererbung:

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

Methodenüberschreibungen und Vererbung von einer anderen Klasse:

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

Wie lerne ich die Verwendung von Prototypen kennen?

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. Was sind Vorlagenliterale?


Vorlagenliterale sind eine relativ neue Methode zum Erstellen von Zeichenfolgen in JS. Vorlagenliterale werden mit doppelten Backticks (``) erstellt:

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

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

In Vorlagenliteralen müssen wir uns nicht in einfache Anführungszeichen setzen.
// ES5
var lastWords = '\n'
    + ' I \n'
    + ' am \n'
    + 'Iron Man \n'

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

In ES6 müssen wir die Escape-Sequenz "\ n" nicht verwenden, um die Zeile zu speisen.

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

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

In ES6 müssen wir keine Zeichenfolgenverkettung verwenden, um Text mit einer Variablen zu kombinieren. Wir können den Ausdruck $ {expr} verwenden, um den Wert der Variablen abzurufen.

46. ​​Was ist Objektzerstörung?


Die Destrukturierung ist eine relativ neue Methode zum Abrufen (Abrufen) der Werte eines Objekts oder Arrays.

Nehmen wir an, wir haben ein Objekt wie dieses:

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

Zuvor haben wir zum Erstellen der Eigenschaften eines Objekts Variablen für jede Eigenschaft erstellt. Es war sehr langweilig und sehr nervig:

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

Durch die Verwendung der Destrukturierung wird der Code sauberer und benötigt weniger Zeit. Die Destrukturierungssyntax lautet wie folgt: Wir schließen die Objekteigenschaften, die wir erhalten möchten, in geschweifte Klammern ({}) und, wenn es sich um ein Array handelt, in eckige Klammern ([]) ein:

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

Verwenden Sie "propertyName: newName", um den Variablennamen zu ändern:

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

Verwenden Sie "propertyName = 'defaultValue'", um Variablen Standardwerte zuzuweisen:

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

47. Was sind Module?


Mit Modulen können Sie Code aus verschiedenen Dateien kombinieren (verwenden) und müssen nicht den gesamten Code in einer großen Datei speichern. Bevor Module in JS erschienen, gab es zwei beliebte Modulsysteme zur Unterstützung von Code:

  • CommonJS - Nodejs
  • AMD (AsyncronousModuleDefinition) - Browser

Die Syntax der Module ist sehr einfach: Wir verwenden den Import, um Funktionen oder Werte aus einer anderen Datei oder Dateien zu importieren, und den Export, um ihn zu exportieren.

Exportfunktionalität in eine andere Datei (benannter 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);
}

Importieren Sie Funktionen in eine andere Datei:

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

Standardexport:

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

Importieren:

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

Dies ist die grundlegende Verwendung von Modulen. Ich bin nicht auf Details eingegangen, weil mein Beitrag bereits zu groß ist.

48. Was ist ein Set-Objekt?


Mit dem Set-Objekt können Sie eindeutige Werte, Grundelemente und Objektreferenzen speichern. Noch einmal: Es können nur eindeutige Werte zu Set hinzugefügt werden. Es überprüft die darin gespeicherten Werte mit dem SameZeroValue-Algorithmus.

Eine Set-Instanz wird mit dem Set-Konstruktor erstellt. Wir können ihm auch einige Werte beim Erstellen übergeben:

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

Wir können Set mit der add-Methode Werte hinzufügen. Da die add-Methode zurückgegeben werden kann, können wir eine Kette von Aufrufen verwenden:

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

Wir können Werte aus Set mit der Löschmethode löschen:

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

Wir können mit der Methode has nach einer Eigenschaft in Set suchen:

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

Verwenden Sie die Größenmethode, um die Länge von Set zu ermitteln:

set2.size // 10

Die Löschmethode löscht Set:

set2.clear() // 

Wir können Set verwenden, um doppelte Werte in einem Array zu entfernen:

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. Was ist eine Rückruffunktion?


Die Rückruffunktion ist eine Funktion, deren Aufruf für die Zukunft verschoben wird (tritt unter bestimmten Bedingungen auf, z. B. wenn ein Ereignis eintritt).

const btnAdd = document.getElementById('btnAdd')

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

Im Beispiel warten wir auf ein "Klick" -Ereignis für ein Element mit der Kennung "btnAdd". Durch Klicken wird die Funktion clickCallback aufgerufen. Die Rückruffunktion fügt den Daten oder Ereignissen einige Funktionen hinzu. Den Reduzierungs-, Filter- und Zuordnungsmethoden wird als zweites Argument eine Rückruffunktion übergeben. Eine gute Analogie zum Rückruf ist die folgende Situation: Sie rufen jemanden an, er antwortet nicht, Sie hinterlassen ihm eine Nachricht und warten, bis er zurückruft. Ein Anruf oder eine Nachricht ist ein Ereignis oder Daten, und ein Rückruf ist die Erwartung (Antizipation) eines Rückrufs.

50. Was sind Versprechen?


Versprechen sind eine Möglichkeit, mit asynchronem Code in JS zu arbeiten. Sie geben das Ergebnis einer asynchronen Operation zurück. Es wurden Versprechen erfunden, um das Problem der sogenannten Hölle der Rückruffunktionen zu lösen.

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

Die Probleme mit diesem Ansatz beginnen, wenn wir der ersten (innerhalb der ersten), dann einer weiteren usw. eine weitere asynchrone Operation hinzufügen müssen. Als Ergebnis erhalten wir einen unordentlichen und unlesbaren Code:

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

Und so sieht es mit Versprechungen aus:

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

Versprechen hat vier Bedingungen:

  • Warten ist der Ausgangszustand eines Versprechens. Das Ergebnis des Versprechens ist unbekannt, da der Vorgang nicht abgeschlossen ist.
  • Fertig - Asynchroner Vorgang abgeschlossen, es gibt ein Ergebnis.
  • Abgelehnt - Asynchroner Vorgang fehlgeschlagen, es gibt einen Grund.
  • Abgeschlossen - abgeschlossen oder abgelehnt.

Der Promise-Konstruktor akzeptiert das Auflösen und Ablehnen als Parameter. Bei der Auflösung wird das Ergebnis der Operation aufgezeichnet, bei Ablehnung der Grund für den Fehler der Operation. Das Ergebnis kann in der .then-Methode verarbeitet werden, der Fehler kann in der .catch-Methode verarbeitet werden. Die .then-Methode gibt auch ein Versprechen zurück, sodass wir eine Kette verwenden können, die aus mehreren .then besteht.

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

Wir können eine Hilfsfunktion erstellen, um eine asynchrone Operation vom Rückruf in ein Versprechen umzuwandeln. Es wird wie util von Node.js funktionieren ("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))

Mehr über Versprechen können Sie hier und hier lesen .

51. Was ist asynchron / warten?


Async / await ist eine relativ neue Methode zum Schreiben von asynchronem (nicht blockierendem) Code in JS. Sie sind in ein Versprechen gehüllt. Es macht Code lesbarer und sauberer als Versprechen und Rückruffunktionen. Um jedoch async / await verwenden zu können, müssen Sie die Versprechen gut kennen.

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

Denken Sie daran: Wenn Sie das Schlüsselwort async verwenden, bevor eine Funktion es zwingt, ein Versprechen zurückzugeben:

const giveMeOne = async () = 1

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

Das Schlüsselwort await kann nur innerhalb einer asynchronen Funktion verwendet werden. Die Verwendung von await in einer anderen Funktion führt zu einem Fehler. Warten Sie, bis der Ausdruck rechts beendet ist, um seinen Wert vor der nächsten Codezeile zurückzugeben.

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

Lesen Sie hier und hier mehr über async / await .

52. Was ist der Unterschied zwischen einem Spread-Operator und einem Rest-Operator?


Die Anweisungenpread und rest haben dieselbe Syntax ("..."). Der Unterschied liegt in der Tatsache, dass wir mit Hilfe von Spread die Daten des Arrays übertragen oder auf andere Daten verteilen und mit Hilfe von Rest alle Parameter der Funktion abrufen und in das Array einfügen (oder einige der Parameter extrahieren).

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

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

In diesem Beispiel verwenden wir Spread, wenn wir die Add-Funktion mit den Nums-Array-Daten aufrufen. Der Wert der Variablen "a" ist 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

Hier rufen wir die Funktion add mit einer beliebigen Anzahl von Argumenten auf. Add gibt die Summe dieser Argumente zurück.

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

In diesem Beispiel verwenden wir rest, um eine beliebige Anzahl von Parametern außer dem ersten in das andere Array einzufügen.

53. Was sind die Standardparameter?


Dies ist eine relativ neue Methode zum Definieren von Standardvariablenwerten.

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

Sie können Destrukturierung verwenden:

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]

Wir können sogar die Standardparameter verwenden, die an derselben Stelle deklariert wurden:

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

54. Was ist ein Objekt-Wrapper (Wrapper-Objekte)?


Die Grundelemente string, number und boolean haben Eigenschaften und Methoden, obwohl sie keine Objekte sind:

let name = 'marko'

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

Name ist eine Zeichenfolge (primitiver Typ), die keine Eigenschaften und Methoden hat. Wenn wir jedoch die toUpperCase () -Methode aufrufen, führt dies nicht zu einem Fehler, sondern zu „MARKO“.

Der Grund für dieses Verhalten ist, dass der Name vorübergehend in ein Objekt konvertiert wird. Jedes Grundelement außer null und undefiniert hat ein Wrapper-Objekt. Solche Objekte sind String, Number, Boolean, Symbol und BigInt. In unserem Fall hat der Code die folgende Form:

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

Ein temporäres Objekt wird nach Abschluss der Arbeit mit einer Eigenschaft oder Methode verworfen.

55. Was ist der Unterschied zwischen implizitem und explizitem Zwang?


Implizite Konvertierung ist eine Möglichkeit, einen Wert ohne unser Wissen (Teilnahme) auf einen anderen Typ zu übertragen.

Angenommen, wir haben Folgendes:

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

Das Ergebnis der ersten console.log ist 16. In anderen Sprachen würde dies zu einem Fehler führen, aber in JS 1 wird es in eine Zeichenfolge konvertiert und von 6 verkettet (angehängt). Wir haben nichts getan, die Konvertierung erfolgte automatisch.

Das Ergebnis des zweiten console.log ist 1. False wurde in 0 konvertiert, true in 1. 0 + 1 = 1.

Das Ergebnis des dritten console.log ist 12. Zeile 2 wurde vor dem Multiplizieren mit 6 in eine Zahl konvertiert.

Explizite Konvertierung impliziert unsere Teilnahme an Umwandeln des Werts in einen anderen Typ:

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

In diesem Beispiel verwenden wir parseInt, um String 6 in eine Zahl umzuwandeln, addieren dann die beiden Zahlen und erhalten 7.

56. Was ist NaN? Wie überprüfe ich, ob der Wert NaN ist?


NaN oder nicht Eine Zahl (keine Zahl) ist der Wert, der als Ergebnis einer numerischen Operation für einen nicht numerischen Wert erhalten wird:

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 verfügt über eine integrierte isNaN-Methode, mit der Sie überprüfen können, ob der Wert NaN ist, die sich jedoch recht seltsam verhält:

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

Das Ergebnis aller console.log ist wahr, obwohl keiner der Werte NaN ist.

ES6 empfiehlt die Verwendung der Number.isNaN-Methode, um zu überprüfen, ob der Wert NaN ist. Wir können auch eine Hilfsfunktion schreiben, um das Problem der „NaN-Ungleichung für sich selbst“ zu lösen:

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

57. Wie überprüfe ich, ob ein Wert ein Array ist?


Verwenden Sie dazu die Array.isArray-Methode:

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

Wenn die Umgebung, in der Sie arbeiten, diese Methode nicht unterstützt, können Sie die folgende Polydatei verwenden:

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

58. Wie kann man überprüfen, ob eine Zahl gerade ist, ohne Modulo-Division oder Division mit Rest (Operator "%") zu verwenden?


Um dieses Problem zu lösen, können Sie den Operator "&" (binär und) verwenden. Der Operator & vergleicht Operanden als Binärwerte.

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

0 in der binären Notation ist 000
1 - dies ist 001
2 - 010
3 - 011
4 - 100
5 - 101
6 - 110
7 - 111
usw.



Console.log (5 & 1) gibt 1 zurück. Zuerst konvertiert der Operator & beide Zahlen in Binärwerte, 5 wird zu 101, 1 wird zu 001. Dann wird ein bitweiser Vergleich durchgeführt:



Vergleichen Sie 1 und 0, wir erhalten 0.
Vergleichen Sie 0 und 0 , wir erhalten 0.
Vergleichen Sie 1 und 1, wir erhalten 1.
Konvertieren Sie den Binärwert in eine Ganzzahl, wir erhalten 1.

Wenn Ihnen diese Informationen zu kompliziert erscheinen, können wir das Problem mit der rekursiven Funktion lösen:

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

59. Wie kann das Vorhandensein einer Eigenschaft in einem Objekt festgestellt werden?


Es gibt drei Möglichkeiten, dies zu tun.

Der erste Weg ist die Verwendung des Operators in:

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

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

Die zweite Möglichkeit ist die Verwendung der hasOwnProperty-Methode:

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

Die dritte ist die Indexnotation des Arrays:

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

60. Was ist AJAX?


AJAX oder Asyncronous JavaScript and XML ist eine Reihe miteinander verbundener Technologien, mit denen Sie im asynchronen Modus mit Daten arbeiten können. Dies bedeutet, dass wir Daten an den Server senden und von diesem empfangen können, ohne die Webseite neu zu laden.

AJAX verwendet die folgenden Technologien:
HTML - Webseitenstruktur.
CSS - Webseitenstile.
JavaScript - Seitenverhalten und Arbeit mit dem DOM.
XMLHttpRequest API - Senden und Empfangen von Daten vom Server.
PHP, Python, Nodejs - eine Art Serversprache.

61. Wie erstelle ich ein Objekt in JS?


Objektliteral:

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

o.greeting // Hi, I'm Mark

Konstruktorfunktion:

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

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. Was ist der Unterschied zwischen den Methoden Object.freeze und Object.seal?


Der Unterschied besteht darin, dass wir bei Verwendung der Object.freeze-Methode die Eigenschaften des Objekts nicht ändern oder bearbeiten können und bei Verwendung von Object.seal eine solche Möglichkeit haben.

63. Was ist der Unterschied zwischen dem Operator in und der Methode hasOwnProperty?


Der Unterschied besteht darin, dass der Operator "in" nicht nur im Objekt selbst, sondern auch in seinen Prototypen und der Methode hasOwnProperty - nur im Objekt - nach dem Vorhandensein einer Eigenschaft sucht.

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. Welche Techniken zum Arbeiten mit asynchronem Code in JS kennen Sie?


  • Rückrufe
  • Versprechen Versprechen).
  • Async / warten.
  • Bibliotheken wie async.js, blueprint, q, co.

65. Was ist der Unterschied zwischen einer normalen Funktion und einem funktionalen Ausdruck?


Nehmen wir an, wir haben Folgendes:

hoistedFunc()
notHoistedFunc()

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

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

Ein Aufruf von notHoistedFunc führt zu einem Fehler, ein Aufruf von hoistedFunc jedoch nicht, da hoistedFunc "auftaucht" und in den globalen Bereich aufsteigt, notHoistedFunc jedoch nicht.

66. Wie rufe ich eine Funktion in JS auf?


In JS gibt es vier Möglichkeiten, eine Funktion aufzurufen. Der Aufruf definiert den Wert dieser oder des "Eigentümers" der Funktion.

Aufruf als Funktion. Wenn eine Funktion als Methode, Konstruktor oder unter Verwendung der Apply- oder Call-Methoden aufgerufen wird, wird sie als Funktion aufgerufen. Der Eigentümer einer solchen Funktion ist das Fensterobjekt:

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

Aufruf als Methode. Wenn eine Funktion eine Eigenschaft eines Objekts ist, nennen wir sie eine Methode. Wenn eine Methode aufgerufen wird, wird dieses Objekt zum Objekt dieser Methode:

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

details.getName() // Marko,  this   details

Aufruf als Konstruktor. Wenn eine Funktion mit dem Schlüsselwort "new" aufgerufen wird, nennen wir diese Funktion einen Konstruktor. Dadurch wird ein leeres Objekt erstellt, dessen Wert Folgendes ist:

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)

Ein Aufruf mit den Methoden apply oder call. Wir verwenden diese Methoden, wenn wir den Wert dieser oder des Eigentümers einer Funktion explizit bestimmen möchten:

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. Was ist Auswendiglernen oder Auswendiglernen?


Memoization ist die Technik zum Erstellen einer Funktion, die sich zuvor berechnete Ergebnisse oder Werte merken kann. Der Vorteil der Memoisierung besteht darin, dass wir vermeiden, eine Funktion mit denselben Argumenten erneut auszuführen. Der Nachteil ist, dass wir gezwungen sind, zusätzlichen Speicher zuzuweisen, um die Ergebnisse zu speichern.

68. Wie würden Sie die Hilfsfunktion des Auswendiglernen implementieren?


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

Wir haben die Memoization-Funktion mit einem Argument implementiert. Machen wir es "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. Warum gibt typeof null ein Objekt zurück? Wie überprüfe ich, ob ein Wert null ist?


typeof null == 'object' gibt aus historischen Gründen immer true zurück. Es gab einen Vorschlag, diesen Fehler durch Ändern von typeof null = 'object' in typeof null = 'null' zu beheben, der jedoch im Interesse der Aufrechterhaltung der Abwärtskompatibilität abgelehnt wurde (eine solche Änderung würde eine große Anzahl von Fehlern mit sich bringen).

Um zu überprüfen, ob der Wert null ist, können Sie den strengen Gleichheitsoperator (===) verwenden:

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

70. Wofür wird das Schlüsselwort "neu" verwendet?


Das Schlüsselwort "new" wird in Konstruktorfunktionen verwendet, um ein neues Objekt (eine neue Instanz der Klasse) zu erstellen.

Nehmen wir an, wir haben einen Code wie diesen:

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

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

Das Schlüsselwort "neu" macht 4 Dinge:

  1. Erstellt ein leeres Objekt.
  2. Bindet diesen Wert daran.
  3. Eine Funktion erbt von functionName.prototype.
  4. Gibt dies zurück, sofern nicht anders angegeben.

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


All Articles