Ich veröffentliche jeden Tag mehrere Multiple-Choice-Fragen über JavaScript auf meinem Instagram-Account, die ich nun auch hier veröffentliche.
Von einfach bis fortgeschritten: teste, wie gut du JavaScript kennst, frische dein Wissen auf oder bereite dich auf ein Vorstellungsgespräch vor! 💪 🚀 Ich werde dieses Repo regelmäßig mit neuen Fragen erweitern. Die Antworten sind unterhalb der Fragen versteckt. Du kannst einfach darauf klicken, um die Antworten anzuzeigen. Viel Glück ❤️
Kontaktiert mich, wenn ihr möchtet! 😊
Instagram || Twitter || LinkedIn || Blog
Benutzt die Fragen und Lösungen in einem Projekt! 😃 Ich würde mich sehr freuen, wenn ihr dieses Repo verlinkt. Ich erstelle die Fragen und antworten (ja, ich bin traurig, lol) und die Community hilft mir unglaublich dabei, das ganze zu pflegen und verbessern! 💪🏼 Danke und habt Spaß! |
---|
Alle 20 Übersetzungen anzeigen 🇸🇦🇪🇬🇧🇦🇩🇪🇪🇸🇫🇷🇮🇩🇯🇵🇰🇷🇳🇱🇧🇷🇷🇺🇹🇭🇹🇷🇺🇦🇻🇳🇨🇳🇹🇼🇽🇰
function sayHi() {
console.log(name);
console.log(age);
var name = "Lydia";
let age = 21;
}
sayHi();
- A:
Lydia
undundefined
- B:
Lydia
undReferenceError
- C:
ReferenceError
und21
- D:
undefined
undReferenceError
Antwort
Innerhalb der Funktion wird zuerst der name
mit dem var
Keyword gesetzt. Das bedeuted, dass die Variable mit dem Standardwert undefined
gehoisted wird (Speicher wird während der Erstellung bereitgestellt), bis zu der Zeile, wo wir die Variable definieren. Da wir die Variable auf der Zeile, wo wir den name
loggen noch nicht gesetzt haben, ist dieser noch undefined
.
Variablen mit dem let
(oder const
) Keyword werden ebenfalls gehoisted, aber im Gegensatz zu var
werden diese nicht initialisiert. Auf sie können wir daher nicht zugreifen, bevor sie definiert wurden. JavaScript wirft einen ReferenceError
aus.
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1);
}
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1);
}
- A:
0 1 2
und0 1 2
- B:
0 1 2
und3 3 3
- C:
3 3 3
und0 1 2
Antwort
Aufgrund der Event Queue in JavaScript, wird die Callback Funktion in setTimeout
nach der Schleife ausgeführt. Da die Variable i
in der ersten Schleife mit dem var
Keyword definiert wurde, ist dieser Wert global verfügbar. Während der Schleife wird der Wert von i
jedesmal mithilfe des ++
Operators um 1
erhöht. Zu dem Zeitpunkt, wenn die Callback Funktion in setTimeout
aufgerufen wird, ist i
gleich 3
im ersten Beispiel.
In der zweiten Schleife wurde die Variable i
mit dem let
Keyword definiert: Variablen, die mit let
(oder const
) deklariert werden sind block-scoped (Ein Block ist alles zwischen { }
). Während jedem Durchlauf bekommt i
einen neuen Wert zugewiesen, der jeweils innerhalb des Scopes der Schleife liegt.
const shape = {
radius: 10,
diameter() {
return this.radius * 2;
},
perimeter: () => 2 * Math.PI * this.radius,
};
shape.diameter();
shape.perimeter();
- A:
20
und62.83185307179586
- B:
20
undNaN
- C:
20
und63
- D:
NaN
und63
Antwort
Merke, dass der Wert von diameter
eine reguläre Funktion ist, während der Wert von perimeter
eine Arrow Function ist.
In Arrow Functions bezieht sich das this
Keyword auf den aktuellen Scope, was bei regulären Funktionen nicht der Fall ist. Das bedeutet, wenn wir perimeter
aufrufen, bezieht es sich nicht auf das shape Object, sondern auf den umliegenden Scope (zum Beispiel window
).
Es gibt keinen Wert radius
in dem Object, daher wird undefined
zurückgegeben.
+true;
!"Lydia";
- A:
1
undfalse
- B:
false
undNaN
- C:
false
undfalse
Antwort
Das unäre Plus versucht einen Operand zu einer Nummer umzuwandeln. true
ist 1
und false
ist 0
.
Der String 'Lydia'
ist truthy. Was wir eigentlich fragen ist: "ist dieser truthy Wert falsy?". Die Antwort ist false
.
const bird = {
size: "small",
};
const mouse = {
name: "Mickey",
small: true,
};
- A:
mouse.bird.size
ist nicht korrekt - B:
mouse[bird.size]
ist nicht korrekt - C:
mouse[bird["size"]]
ist nicht korrekt - D: Keine der Antworten ist korrekt.
Antwort
In JavaScript sind alle Object Keys strings (außer bei Symbols). Selbst wenn diese nicht als strings getyped sind, werden sie im Endeffekt zu Strings konvertiert.
JavaScript interpretiert lediglich Aussagen. Wenn wir Bracket Notation verwenden, sieht JavaScript so zuerst eine öffnende eckige Klammer [
und geht weiter, bis es eine schließende eckige Klammer ]
findet. Erst dann wird die Aussage evaluiert.
mouse[bird.size]
: Erst wird bird.size
evaluiert, was "small"
zurück gibt. mouse["small"]
gibt true
zurück.
Mit der Dot Notation ist das nicht der Fall. mouse
hat keinen Key namens bird
, was bedeutet, dass mouse.bird
undefined
ist. Dann fragen wir nach der size
mit Dot Notation: mouse.bird.size
. Da mouse.bird
undefined
ist, fragen wir eigentlich nach undefined.size
. Das ist fehlerhaft und wirft daher einen Fehler, wie zum Beispiel Cannot read property "size" of undefined
zurück.
let c = { greeting: "Hey!" };
let d;
d = c;
c.greeting = "Hello";
console.log(d.greeting);
- A:
Hello
- B:
Hey
- C:
undefined
- D:
ReferenceError
- E:
TypeError
Antwort
In JavaScript interagieren alle Objekte durch Referenz, wenn diese gleich sind.
Zuerst hält die Variable c
ein Object. Später wird d
die selbe Referenz zugewiesen wie c
.
Wenn ein Object geändert wird, werden alle Referenzen zu diesem Object ebenfalls aktualisiert.
let a = 3;
let b = new Number(3);
let c = 3;
console.log(a == b);
console.log(a === b);
console.log(b === c);
- A:
true
false
true
- B:
false
false
true
- C:
true
false
false
- D:
false
true
true
Antwort
new Number()
ist ein eingebauter Function Constructor. Auch wenn der Wert wie eine Nummer aussieht, ist es in Wirklichkeit keine Nummer, sondern beinhaltet eine Menge zusätzlicher Werte und ist daher ein Object.
Wenn wir ==
nutzen wird nur geprüft, ob der Wert gleich ist. Da beide den Wert 3
haben, wird true
zurückgegeben.
Wenn wir aber ===
nutzen müssen sowohl der Wert als auch der Typ übereinstimmen. Das ist false
, da new Number()
keine Nummer, sondern ein Object ist.
class Chameleon {
static colorChange(newColor) {
this.newColor = newColor;
return this.newColor;
}
constructor({ newColor = "green" } = {}) {
this.newColor = newColor;
}
}
const freddie = new Chameleon({ newColor: "purple" });
freddie.colorChange("orange");
- A:
orange
- B:
purple
- C:
green
- D:
TypeError
Antwort
Die colorChange
Funktion ist statisch (static
). Statische Methoden existieren nur am Constructor wo sie erstellt wurden und können nicht an ihre Kinder weitergegeben werden. Da freddie
ein Kind ist, wird die Funktion nicht runter gereicht und ist daher auch nicht in der freddie
Instanz verfügbar. Ein TypeError
wird zurückgeworfen.
let greeting;
greetign = {}; // Typo!
console.log(greetign);
- A:
{}
- B:
ReferenceError: greetign is not defined
- C:
undefined
Antwort
Das Object wird geloggt, da wir ein leeres Object am globalen Object erstellt haben. Als wir uns bei greeting
verschrieben haben (als greetign
) hat JavaScript das als neues Objekt global.greetign = {}
(oder window.greetign = {}
im Browser) angesehen.
Um das zu verhindern, können wir "use strict"
verwenden. Das stellt sicher, dass eine Variable erst definiert sein muss, bevor dieser ein Wert zugewiesen werden kann.
function bark() {
console.log("Woof!");
}
bark.animal = "dog";
- A: Nichts, das ist absolut in Ordnung.
- B:
SyntaxError
. Man kann einer Funktion keine Properties in der Form zuweisen. - C:
undefined
- D:
ReferenceError
Antwort
In JavaScript ist das ohne Weiteres möglich, da Funktionen Objekte sind. (Alle Typen außer primitiven Typen sind Objekte)
Eine Funktion ist ein spezieller Typ eines Objekts. Der Code, den wir schreiben ist keine eigentliche Funktion, sondern ein Object mit Properties. Die Property ist aufrufbar.
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
const member = new Person("Lydia", "Hallie");
Person.getFullName = function() {
return `${this.firstName} ${this.lastName}`;
};
console.log(member.getFullName());
- A:
TypeError
- B:
SyntaxError
- C:
Lydia Hallie
- D:
undefined
undefined
Antwort
Man kann keine Properties einem Constructor zuweisen, wie es bei normalen Objects der Fall ist. Wenn man ein Feature allen Objects zugleich zuweisen möchte, muss man den Prototype verwenden. In diesem Fall also:
Person.prototype.getFullName = function() {
return `${this.firstName} ${this.lastName}`;
};
So hätte member.getFullName()
funktioniert. Warum ist das von Vorteil? Sagen wir, wir hätten diese Methode dem Constructor selbst zugewiesen, aber vielleicht benötigt nicht jede Instanz von Person
diese Methode. So hätte das eine Menge Arbeitsspeicher verschwendet, weil jede Instanz die Property zugewiesen bekommt, auch wenn sie diese gar nicht benötigt.
Stattdessen haben wir sie nur dem Prototype zugewiesen, sodass sie nur an einer Stelle im Arbeitsspeicher hinterlegt ist, aber dennoch haben alle Instanzen Zugriff darauf.
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
const lydia = new Person("Lydia", "Hallie");
const sarah = Person("Sarah", "Smith");
console.log(lydia);
console.log(sarah);
- A:
Person {firstName: "Lydia", lastName: "Hallie"}
undundefined
- B:
Person {firstName: "Lydia", lastName: "Hallie"}
undPerson {firstName: "Sarah", lastName: "Smith"}
- C:
Person {firstName: "Lydia", lastName: "Hallie"}
und{}
- D:
Person {firstName: "Lydia", lastName: "Hallie"}
undReferenceError
Antwort
Für sarah
haben wir nicht das new
Keyword verwendet. Wenn wir new
verwenden, bezieht sich das auf das neue, leere Object, welches wir erstellen. Wenn wir allerdings das new
Keyword nicht verwenden, bezieht es sich auf das globale Objekt.
Wir haben this.firstName
den Wert "Sarah"
zugewiesen und this.lastName
den Wert "Smith"
. Was wir damit eigentlich zugewiesen haben, ist global.firstName = 'Sarah'
und global.lastName = 'Smith'
. sarah
selbst ist daher undefined
.
- A: Target > Capturing > Bubbling
- B: Bubbling > Target > Capturing
- C: Target > Bubbling > Capturing
- D: Capturing > Target > Bubbling
Antwort
Während der capturing Phase geht das Event durch die Elternelemente bis hin zum Zielelement. Wenn dann das Ziel (target) erreicht ist, beginnt die bubbling Phase.
- A: wahr
- B: falsch
Antwort
Alle Objekte haben Prototypes, außer dem Basis Objekt. Das Basis Objekt hat Zugriff auf einige Methoden und Properties, wie zum Beispiel .toString
. Das ist der Grund, warum wir eingebaute JavaScript Methoden nutzen können. All diese Methoden sind am Prototype verfügbar. Obwohl JavaScript diese nicht direkt am Objekt finden kann, folgt es der Prototype Chain, bis es die Property findet und damit verfügbar macht.
function sum(a, b) {
return a + b;
}
sum(1, "2");
- A:
NaN
- B:
TypeError
- C:
"12"
- D:
3
Antwort
JavaScript ist eine Sprache mit dynamischen Typen, was bedeutet, dass wir Variablen keine spezifischen Typen zuweisen. Werte können automatisch in einen anderen Typ umgewandelt werden, was implicit type coercion genannt wird. Coercion (dt. "Zwang") ist die Umwandlung von einem Typ zu einem anderen.
In diesem Beispiel wandelt JavaScript die Nummer 1
in einem String um, sodass die Funktion Sinn ergibt und einen Wert zurückgeben kann. Während der Addition eines numerischen Types (1
) mit einem String ('2'
) wird die Nummer wie ein String behandelt. Wir können Strings mit einem Plus Symbol zusammensetzen, zum Beispiel: "Hello" + "World"
. Genau das passiert hier, sodass "1" + "2"
einen Wert von "12"
zurückgibt.
let number = 0;
console.log(number++);
console.log(++number);
console.log(number);
- A:
1
1
2
- B:
1
2
2
- C:
0
2
2
- D:
0
1
2
Antwort
Der Postfix Unary Operator ++
:
- gibt den Wert zurück (hier:
0
) - erhöht den Wert (
number
ist jetzt1
)
Der Prefix Unary Operator ++
:
- erhöht den Wert (
number
ist jetzt2
) - gibt den Wert zurück (hier:
2
)
Der Output ist daher 0 2 2
.
function getPersonInfo(one, two, three) {
console.log(one);
console.log(two);
console.log(three);
}
const person = "Lydia";
const age = 21;
getPersonInfo`${person} is ${age} years old`;
- A:
"Lydia"
21
["", " is ", " years old"]
- B:
["", " is ", " years old"]
"Lydia"
21
- C:
"Lydia"
["", " is ", " years old"]
21
Antwort
Wenn man Template Literals verwendet ist das erste Argument immer ein Array der String Werte. Die restlichen Argumente bekommen die Werte der übergebenen Expressions zugewiesen.
function checkAge(data) {
if (data === { age: 18 }) {
console.log("You are an adult!");
} else if (data == { age: 18 }) {
console.log("You are still an adult.");
} else {
console.log(`Hmm.. You don't have an age I guess`);
}
}
checkAge({ age: 18 });
- A:
You are an adult!
- B:
You are still an adult.
- C:
Hmm.. You don't have an age I guess
Antwort
Wenn man prüft, ob Werte gleich sind werden Primitives immer anhand ihrer Value verglichen, während Objects anhand der Referenz verglichen werden. JavaScript prüft, ob die Objekte eine Referenz zur gleichen Stelle im Speicher haben.
Die beiden Objekte, die wir hier vergleichen haben das nicht. Das Objekt, welches wir als Parameter übergeben haben bezieht sich auf eine andere Stelle im Speicher, als das Objekt, welches wir verwendet haben um die Werte zu vergleichen.
Deshalb werfen sowohl { age: 18 } === { age: 18 }
als auch { age: 18 } == { age: 18 }
den Wert false
zurück.
function getAge(...args) {
console.log(typeof args);
}
getAge(21);
- A:
"number"
- B:
"array"
- C:
"object"
- D:
"NaN"
Antwort
Der Spread Operator (...args
) gibt ein Array mit Argumenten zurück. Ein Array ist ein Objekt, sodass typeof args
"object"
ausgibt.
function getAge() {
"use strict";
age = 21;
console.log(age);
}
getAge();
- A:
21
- B:
undefined
- C:
ReferenceError
- D:
TypeError
Antwort
Durch "use strict"
kann man sicher stellen, dass man nicht versehentlich globale Variablen definiert. Da wir die Variable age
nie definiert haben und "use strict"
verwenden wirft JavaScript einen reference error aus. Hätten wir "use strict"
nicht verwendet, so hätte es funktioniert, da die property age
dem globalen Objekt zugewiesen worden wäre.
const sum = eval("10*10+5");
- A:
105
- B:
"105"
- C:
TypeError
- D:
"10*10+5"
Antwort
eval
evaluiert Code, der als String übergeben wurde. Falls es, wie in diesem Fall, eine Expression ist, so wird diese Expression auch evaluiert. Die Expression 10 * 10 + 5
gibt damit die nummer 105
aus.
sessionStorage.setItem("cool_secret", 123);
- A: Für immer, der Wert geht nicht verloren.
- B: Wenn der User den Tab schließt.
- C: Wenn der User den Browser schließt, nicht nur den Tab.
- D: Wenn der User den Computer neu startet.
Antwort
Der Wert in sessionStorage
geht verloren, wenn der Tab geschlossen wird.
Wenn man stattdessen localStorage
verwendet, bleibt der Wert für immer bestehend, es sei denn localStorage.clear()
wird ausgeführt.
var num = 8;
var num = 10;
console.log(num);
- A:
8
- B:
10
- C:
SyntaxError
- D:
ReferenceError
Antwort
Mit dem var
Keyword kann man mehrere Variablen mit dem selben Namen definieren. Die Variable hält dann den letzt gesetzten Wert.
Das ist nicht möglich mit let
oder const
, da diese dem Block Scope unterliegen.
const obj = { 1: "a", 2: "b", 3: "c" };
const set = new Set([1, 2, 3, 4, 5]);
obj.hasOwnProperty("1");
obj.hasOwnProperty(1);
set.has("1");
set.has(1);
- A:
false
true
false
true
- B:
false
true
true
true
- C:
true
true
false
true
- D:
true
true
true
true
Antwort
Alle Object Keys (außgenommen Symbols) sind im Endeffekt Strings, selbst, wenn man diese nicht explizit als String definiert. Deshalb gibt obj.hasOwnProperty('1')
auch true
zurück.
Das funktioniert nicht für Set. Da wir keine '1'
in unserem Set haben wirft set.has('1')
den Wert false
zurück. Der Typ von 1
ist numerisch und set.has(1)
gibt daher true
zurück.
const obj = { a: "one", b: "two", a: "three" };
console.log(obj);
- A:
{ a: "one", b: "two" }
- B:
{ b: "two", a: "three" }
- C:
{ a: "three", b: "two" }
- D:
SyntaxError
Antwort
Wenn man zwei Keys mit dem selben Namen hat, wird der erste Key ersetzt. Er wird immernoch an erster Stelle sein, allerdings mit dem zuletzt gesetzten Wert.
26. Der JavaScript Global Execution Context erstellt zwei Dinge: das globale Objekt und das "this" Keyword.
- A: wahr
- B: falsch
- C: kommt darauf an
Antwort
Der Base Execution Context entspricht dem Global Execution Context und ist überall in unserem Code verfügbar.
for (let i = 1; i < 5; i++) {
if (i === 3) continue;
console.log(i);
}
- A:
1
2
- B:
1
2
3
- C:
1
2
4
- D:
1
3
4
Antwort
continue
überspringt einen Durchlauf, wenn eine gewisse Bedingung erfüllt ist und true
zurück gibt.
String.prototype.giveLydiaPizza = () => {
return "Just give Lydia pizza already!";
};
const name = "Lydia";
console.log(name.giveLydiaPizza())
- A:
"Just give Lydia pizza already!"
- B:
TypeError: not a function
- C:
SyntaxError
- D:
undefined
Antwort
String
ist ein eingebauter Constructor, dem wir Properties zuweisen können. Wir haben hier seinem Prototype eine Methode hinzugefügt. Primitive strings werden automatisch durch die String Prototype Function in ein String Objekt umgewandelt. Daher haben alle Strings (String Objects) Zugriff auf diese Methode.
const a = {};
const b = { key: "b" };
const c = { key: "c" };
a[b] = 123;
a[c] = 456;
console.log(a[b]);
- A:
123
- B:
456
- C:
undefined
- D:
ReferenceError
Antwort
Objekt Keys werden automatisch in Strings umgewandelt. Wir versuchen ein Objekt mit dem Wert 123
als Key dem Objekt a
zuzuweisen.
Allerdings wird ein Object, wenn es in einen String umgewandelt wird als "[object Object]"
ausgegeben. Was wir hier also sagen ist, dass a["object Object"] = 123
ist. Wir versuchen das gleiche erneut - c
ist ein anderes Objekt, welches wir implizit zu einem String umwandeln, sodass a["object Object"] = 456
ist.
Dann loggen wir a[b]
, was eigentlich a["object Object"]
ist und gerade von uns zu 456
gesetzt wurde, sodass 456
ausgegeben wird.
const foo = () => console.log("First");
const bar = () => setTimeout(() => console.log("Second"));
const baz = () => console.log("Third");
bar();
foo();
baz();
- A:
First
Second
Third
- B:
First
Third
Second
- C:
Second
First
Third
- D:
Second
Third
First
Antwort
Wir haben eine setTimeout
Funktion, die zuerst ausgeführt wird und dennoch als letztes ausgegeben wird.
Der Grund dafür ist, dass Browser nicht nur die Runtime Engine, sondern auch eine WebAPI
haben. Die WebAPI
stellt uns setTimeout
bereit.
Nachdem die Callback Function an die WebAPI übergeben wurde wird setTimeout
(aber nicht die Callback Function) ausgeführt und aus dem Stack entfernt.
Jetzt wird foo
ausgeführt und "First"
geloggt.
foo
wird aus dem Stack entfernt und baz
wird ausgeführt. "Third"
wird geloggt.
Die WebAPI kann nicht einfach Dinge zum Stack hinzufügen, wenn sie bereit ist, stattdessen wird die Callback Function zur queue hinzugefügt.
Das ist, wo die Event Loop ins Spiel kommt. Die Event Loop betrachtet den Stack und die Task Queue. Wenn der Stack leer ist wird das erste Element in der Queue zum Stack übertragen.
bar
wird ausgeführt, "Second"
wird geloggt und aus dem Stack entfernt.
<div onclick="console.log('first div')">
<div onclick="console.log('second div')">
<button onclick="console.log('button')">
Click!
</button>
</div>
</div>
- A: Äußerer
div
- B: Innerer
div
- C:
button
- D: Ein Array mit allen genesteten Elementen
Antwort
Das am tiefsten genestete Element, welches das Event auslöst ist das Event Target. Man kann den Bubbling Prozess mit event.stopPropagation
anhalten.
<div onclick="console.log('div')">
<p onclick="console.log('p')">
Click here!
</p>
</div>
- A:
p
div
- B:
div
p
- C:
p
- D:
div
Antwort
Wenn wir auf den Paragraph klicken, sehen wir zwei logs: p
und div
. Während der Event Propagation werden drei Phasen ausgeführt: capturing, target und bubbling. Standardmäßig werden Event Handler in der Bubbling Phase ausgeführt (es sei denn man setzt useCapture
auf true
). Die Ausführung beginnt vom tiefsten Element nach Außen.
const person = { name: "Lydia" };
function sayHi(age) {
console.log(`${this.name} is ${age}`);
}
sayHi.call(person, 21);
sayHi.bind(person, 21);
- A:
undefined is 21
Lydia is 21
- B:
function
function
- C:
Lydia is 21
Lydia is 21
- D:
Lydia is 21
function
Antwort
In beiden Fällen können wir das Objekt weiter reichen, auf welches sich das this
Keyword beziehen soll. Allerdings wird .call
sofort ausgeführt.
.bind.
gibt eine Kopie der Funktion mit gebundenem Context zurück und wird daher nicht sofort ausgeführt.
function sayHi() {
return (() => 0)();
}
typeof sayHi();
- A:
"object"
- B:
"number"
- C:
"function"
- D:
"undefined"
Antwort
Die sayHi
Funktion gibt den Wert der sofort ausgeführten Funktion (IIFE) zurück. Die Funktion gibt 0
zurück, was vom Typ "number"
ist.
Es gibt nur 7 eingebaute Typen in JavaScript: null
, undefined
, boolean
, number
, string
, object
, symbol
, und bigint
. "function"
ist kein Typ, weil Funktionen Objekte sind und daher dem Typ "object"
entsprechen.
0;
new Number(0);
("");
(" ");
new Boolean(false);
undefined;
- A:
0
,''
,undefined
- B:
0
,new Number(0)
,''
,new Boolean(false)
,undefined
- C:
0
,''
,new Boolean(false)
,undefined
- D: Alle sind falsy
Antwort
Es gibt nur 6 falsy typen:
undefined
null
NaN
0
''
(leerer String)false
Funktions-Constructor, wie new Number
und new Boolean
sind truthy.
console.log(typeof typeof 1);
- A:
"number"
- B:
"string"
- C:
"object"
- D:
"undefined"
const numbers = [1, 2, 3];
numbers[10] = 11;
console.log(numbers);
- A:
[1, 2, 3, 7 x null, 11]
- B:
[1, 2, 3, 11]
- C:
[1, 2, 3, 7 x empty, 11]
- D:
SyntaxError
Antwort
Wenn Werte einem Element in einem Array zugewiesen werden, die die Länge des Arrays übersteigen, so erstellt JavaScript "empty slots" (leere Stellen). Diese haben den Wert undefined
, aber das Array sieht dann in etwa so aus:
[1, 2, 3, 7 x empty, 11]
abhängig davon wo das Array ausgeführt wird (die Ausgabe ist unterschiedlich für verschiedene Browser, Node, etc.)
(() => {
let x, y;
try {
throw new Error();
} catch (x) {
(x = 1), (y = 2);
console.log(x);
}
console.log(x);
console.log(y);
})();
- A:
1
undefined
2
- B:
undefined
undefined
undefined
- C:
1
1
2
- D:
1
undefined
undefined
Antwort
Der catch
Block erhält ein Argument x
. Das ist nicht das selbe x
wie die Variable, der wir Argumente zuweisen. Die Variable x
ist block-scoped.
Später setzen wir die block-scoped Variable gleich 1
, und setzen ebenfalls den Wert der Variable y
. Jetzt loggen wir die block-scoped Variable x
mit dem Wert 1
.
Außerhalb des catch
Blocks ist x
noch immer undefined
und y
ist 2
. Wenn wir console.log(x)
außerhalb des catch
Block ausführen, wird für x
der Wert undefined
und für y
der Wert 2
geloggt.
- A: Primitive oder Object
- B: Function oder Object
- C: Fangfrage: nur Objects!
- D: Number oder Object
Antwort
JavaScript hat nur primitive Typen und Objekte.
Primitive Typen sind boolean
, null
, undefined
, bigint
, number
, string
, und symbol
.
Was einen primitiven Typ von einem Objekt unterscheidet ist, dass Primitive keine Properties oder Methoden haben, obwohl zum Beispiel 'foo'.toUpperCase()
zu 'FOO'
wird und keinen TypeError
auswirft. Der Grund dafür ist, wenn man eine Property oder Method an einem primitiven Typ wie einem String ausführt, legt JavaScript eine Wrapper Class um das String Objekt, die danach sofort wieder entfernt wird, wenn die Expression ausgeführt wurde. Alle primitiven Typen außer null
und undefined
weisen dieses Verhalten auf.
[[0, 1], [2, 3]].reduce(
(acc, cur) => {
return acc.concat(cur);
},
[1, 2],
);
- A:
[0, 1, 2, 3, 1, 2]
- B:
[6, 1, 2]
- C:
[1, 2, 0, 1, 2, 3]
- D:
[1, 2, 6]
Antwort
[1, 2]
ist unser ursprünglicher Wert. Zusammen mit dem ersten acc
ist das der Wert, mit dem wir beginnen. Während dem ersten Durchlauf ist acc
gleich [1, 2]
, und cur
ist [0, 1]
. Wir verbinden diese, was [1, 2, 0, 1]
ergibt.
Dann entspricht acc
gleich [1, 2, 0, 1]
und cur
ist gleich [2, 3]
. Wir verbinden diese und bekommen [1, 2, 0, 1, 2, 3]
.
!!null;
!!"";
!!1;
- A:
false
true
false
- B:
false
false
true
- C:
false
true
true
- D:
true
true
false
Antwort
null
ist falsy. !null
gibt true
zurück. !true
gibt false
zurück.
""
ist falsy. !""
gibt true
zurück. !true
gibt false
zurück.
1
ist truthy. !1
gibt false
zurück. !false
gibt true
zurück.
setInterval(() => console.log("Hi"), 1000);
- A: Eine unique id
- B: Die definierte Anzahl von Millisekunden
- C: Die Callback Function
- D:
undefined
Antwort
Es gibt eine unique id zurück. Diese id kann zum Beispiel verwendet werden um das Interval mit der clearInterval()
Funktion zu leeren.
[..."Lydia"];
- A:
["L", "y", "d", "i", "a"]
- B:
["Lydia"]
- C:
[[], "Lydia"]
- D:
[["L", "y", "d", "i", "a"]]
Antwort
Ein String ist ein Iterable. Der Spread Operator mappt jedes Zeichen eines Iterables zu einem eigenen Element.
function* generator(i) {
yield i;
yield i * 2;
}
const gen = generator(10);
console.log(gen.next().value);
console.log(gen.next().value);
- A:
[0, 10], [10, 20]
- B:
20, 20
- C:
10, 20
- D:
0, 10 und 10, 20
Antwort
Reguläre Funktionen können nicht angehalten werden, wenn sie bereits aufgerufen wurden. Eine Generator Funktion kann dagegen auch angehalten werden, nachdem sie aufgerufen wurde und später fortgesetzt werden, wo sie angehalten wurde. Jedes Mal, wenn eine Generator Funktion ein yield
Keyword findet, wirft die Funktion den danach ermittelten Wert aus. Wichtig: yield ist nichtdas selbe wie return.
Zuerst initialisieren wir die Generator Funktion mit i
gleich 10
. Wir rufen die Generator Funktion mit der next()
Methode auf. Beim ersten Aufruf der Generator Funktion is i
gleich 10
. Wenn wir bei yield
ankommen wird der Wert von i
ausgegeben. Der Generator wird angehalten und 10
wird geloggt.
Dann wird die Funktion erneut mit der next()
Methode aufgerufen und beginnt von dort, wo sie zuletzt angehalten wurde, nach wie vor mit i
gleich 10
. Jetzt erreichen wir das nächste yield
Keyword bei i * 2
. i
ist gleich 10
, sodass das Ergebnis von 10 * 2
ausgegeben wird, was 20
ist. Das Ergebnis ist 10, 20
.
const firstPromise = new Promise((res, rej) => {
setTimeout(res, 500, "one");
});
const secondPromise = new Promise((res, rej) => {
setTimeout(res, 100, "two");
});
Promise.race([firstPromise, secondPromise]).then(res => console.log(res));
- A:
"one"
- B:
"two"
- C:
"two" "one"
- D:
"one" "two"
Antwort
Wenn wir mehrere Promises in die Promice.race
Methode eingegeben, wird das Promise, welches zuerst gelöst/abgelehnt wird auch hier gelöst/abgelehnt. Die setTimeout
Methode bekommt einen Timer von 500ms für das erste Promise (firstPromise
) übergeben, und 100ms für das zweite Promise (secondPromise
). Das bedeutet, dass secondPromise
mit dem Wert 'two'
zuerst gelöst wird und an res
übergeben wird. Der Wert wird geloggt.
let person = { name: "Lydia" };
const members = [person];
person = null;
console.log(members);
- A:
null
- B:
[null]
- C:
[{}]
- D:
[{ name: "Lydia" }]
Antwort
Zuerst definieren wir die Variable person
mit dem Wert eines Objekts, welches eine name
Property hat.
Dann definieren wir eine Variable namens members
. Wir setzen das erste Element des Arrays gleich dem Wert der person
Variable. Objekte interagieren durch eine Referenz, wenn diese gleichgesetzt werden. Wenn eine Referenz von einer Variable zur anderen gleichgesetzt wird, so wird eine Kopie der Referenz erstellt (Wichtig: nicht die selbe Referenz!)
Dann setzen wir die Variable person
gleich null
.
Wir ändern nur den Wert der Variable person
und nicht das erste Element im Array, da das Element eine andere Referenz als das Objekt hat (Kopie). Das erste Element in members
beinhaltet immernoch die Referenz zum original Objekt. Wenn wir das members
Array loggen ist dieses immernoch der Wert des Objekts, welches dann geloggt wird.
const person = {
name: "Lydia",
age: 21
};
for (const item in person) {
console.log(item);
}
- A:
{ name: "Lydia" }, { age: 21 }
- B:
"name", "age"
- C:
"Lydia", 21
- D:
["name", "Lydia"], ["age", 21]
Antwort
Mit einer for-in
Schleife können wir über Objekt Keys iterieren - in diesem Fall name
und age
. Im Endeffekt sind Objekt Keys Strings (oder Symbols). Bei jedem Durchlauf setzen wir den Wert von item
gleich zum aktuellen Key. Zuerst ist item
gleich name
und wird geloggt. Dann wird item
gleich age
gesetzt und wird geloggt.
console.log(3 + 4 + "5");
- A:
"345"
- B:
"75"
- C:
12
- D:
"12"
Antwort
Operator Assoziativität ist die Reihenfolge, in der der Compiler die Expression evaluiert, entweder links-nach-rechts oder rechts-nach-links. Das funktioniert nur, wenn alle Operatoren die gleiche Priorität haben. Hier haben wir nur einen Operator: +
. Für Addition ist die Assoziativität links-nach-rechts.
3 + 4
wird zuerst errechnet, das Ergebnis ist 7
.
7 + '5'
ergibt "75"
(aufgrund von Coercion). JavaScript wandelt 7
in einen String um (Siehe Frage 15). Zwei Strings werden durch den +
Operator zusammengesetzt."7" + "5"
ergibt "75"
.
const num = parseInt("7*6", 10);
- A:
42
- B:
"42"
- C:
7
- D:
NaN
Antwort
Nur die erste Zahl im String wird ausgegeben. Aufgrund des radix (das zweite Argument definiert, welchen Typ einer Zahl wir parsen wollen: Basis 10, hexadezimal, Octal, Binary, etc.) prüft parseInt
ob die Zeichen im String gültig sind. Wenn ein Zeichen erkannt wird, welches nicht gültig ist, wird der Parse Vorgang beendet und die nachfolgenden Zeichen werden ignoriert.
*
ist keine gültige Nummer, sodass nur "7"
als Dezimal geparsed wird: 7
. num
ist jetzt gleich 7
.
[1, 2, 3].map(num => {
if (typeof num === "number") return;
return num * 2;
});
- A:
[]
- B:
[null, null, null]
- C:
[undefined, undefined, undefined]
- D:
[ 3 x empty ]
Antwort
Wenn man über das Array mappt, ist num
gleich dem Element, welches gerade durchlaufen wird. In diesem Fall sind die Elemente Nummern, sodass die Kondition der If-Schleife typeof num === "number"
erfüllt ist und true
zurück gibt. Die map Funktion erstellt ein neues Array und beinhaltet die Werte der Funktion.
Allerdings geben wir keinen Wert aus. Wenn unsere Funktion keinen Wert ausgibt, ist der Standard "return" undefined
. Für jedes Element im Array wird die Funktion aufgerufen, sodass für jedes Element undefined
ausgegeben wird.
function getInfo(member, year) {
member.name = "Lydia";
year = 1998;
}
const person = { name: "Sarah" };
const birthYear = "1997";
getInfo(person, birthYear);
console.log(person, birthYear);
- A:
{ name: "Lydia" }, "1997"
- B:
{ name: "Sarah" }, "1998"
- C:
{ name: "Lydia" }, "1998"
- D:
{ name: "Sarah" }, "1997"
Antwort
Argumente werden als Wert übergeben, es sei denn ihr Wert ist ein Objekt, dann werden sie als Referenz übergeben. birthYear
wird als Wert übergeben, da es ein String ist und kein Objekt. Wenn Argumente als Wert übergeben werden, wird eine Kopie des Wertes erstellt (Siehe Frage 46).
Die Variable birthYear
beinhaltet eine Referenz zum Wert "1997"
. Das Argument year
beinhaltet ebenso eine Referenz zum Wert "1997"
, aber die Werte sind nicht identisch! Wenn wir den Wert von year
ändern, indem wir ihn gleich "1998"
setzen, ändern wir nur den Wert von year
. birthYear
ist immernoch "1997"
.
Der Wert von person
ist ein Objekt, sodass das Argument member
eine Kopie der Referenz des gleichen Objekts hat. Wenn wir also eine Property dessen Objekt member
eine Referenz enthält, wird der Wert von person
ebenso geändert, da beide die gleiche Referenz zum selben Objekt beinhalten. Die Property name
von person
ist jetzt gleich "Lydia"
.
function greeting() {
throw "Hello world!";
}
function sayHi() {
try {
const data = greeting();
console.log("It worked!", data);
} catch (e) {
console.log("Oh no an error!", e);
}
}
sayHi();
- A:
"It worked! Hello world!"
- B:
"Oh no an error: undefined"
- C:
SyntaxError: can only throw Error objects
- D:
"Oh no an error! Hello world!"
Antwort
Mit dem throw
Statement können wir individuelle Fehlermeldungen erstellen und Exceptions erstellen. Eine Exception kann ein String, eine Nummer, ein Boolean oder ein Objekt sein. In diesem Fall ist unsere Exception der String 'Hello world'
.
Mit dem catch
Statement können wir definieren, was passiert, wenn die Exception im try
Block eintritt. Wenn die Exception eintritt wird der String 'Hello world'
ausgegeben. Nun loggen wir e
, was gleich dem String ist. Das Ergebnis ist 'Oh an error: Hello world'
.
function Car() {
this.make = "Lamborghini";
return { make: "Maserati" };
}
const myCar = new Car();
console.log(myCar.make);
- A:
"Lamborghini"
- B:
"Maserati"
- C:
ReferenceError
- D:
TypeError
Antwort
Wenn man eine Property ausgibt ist der Wert der Property gleich dem ausgegeben Wert und nicht dem Wert, der im Constructor definiert wurde. Wir geben den String "Maserati"
aus, sodass myCar.make
gleich "Maserati"
ist.
(() => {
let x = (y = 10);
})();
console.log(typeof x);
console.log(typeof y);
- A:
"undefined", "number"
- B:
"number", "number"
- C:
"object", "number"
- D:
"number", "undefined"
Antwort
let x = y = 10;
ist kurz für:
y = 10;
let x = y;
Wenn wir y
gleich 10
setzen, erstellen wir eigentlich eine Property y
im globalen Objekt (window
im Browser oder global
in Node). Im Browser ist jetzt window.y
gleich 10
.
Dann erstellen wir eine Variable x
mit dem Wert von y
(10
). Variablen, die mit let
erstellt werden sind Block-Scoped, was bedeutet, dass sie nur in dem Block existieren, wo sie erstellt wurden – der hier erstellte Funktion (IIFE) in diesem Fall. Wenn wir den typeof
Operator nutzen ist x
nicht definiert. Wir versuchen auf x
außerhalb des Scopes zuzugreifen, was bedeutet, dass x
"undefined"
ist. console.log(typeof x)
gibt daher "undefined"
aus.
Da wir die Variable y
aber global erstellt haben ist ihr Wert 10
auch hier verfügbar und überall in userem Code aufrufbar. y
ist definiert und beinhaltet einen Wert vom Typ "number"
. console.log(typeof y)
gibt daher "number"
aus.
class Dog {
constructor(name) {
this.name = name;
}
}
Dog.prototype.bark = function() {
console.log(`Woof I am ${this.name}`);
};
const pet = new Dog("Mara");
pet.bark();
delete Dog.prototype.bark;
pet.bark();
- A:
"Woof I am Mara"
,TypeError
- B:
"Woof I am Mara"
,"Woof I am Mara"
- C:
"Woof I am Mara"
,undefined
- D:
TypeError
,TypeError
Antwort
Properties von Objekten können mit dem delete
Keyword entfernt werden, selbst am Prototype. Beim entfernen von Properties am Prototype ist zu beachten, dass diese dann aus der Prototypen-Kette verschwinden. In unserem Fall existiert die bark
Funktion nicht mehr am Prototype nachdem delete Dog.prototype.bark
ausgeführt wurde.
Wenn wir versuchen etwas auszuführen, was keine Funktion ist, wird ein TypeError
ausgeworfen. In diesem Fall TypeError: pet.bark is not a function
, da pet.bark
undefined
ist.
const set = new Set([1, 1, 2, 3, 4]);
console.log(set);
- A:
[1, 1, 2, 3, 4]
- B:
[1, 2, 3, 4]
- C:
{1, 1, 2, 3, 4}
- D:
{1, 2, 3, 4}
Antwort
Das Set
Objekt ist eine Sammlung von eindeutigen Werten: jeder Wert kann nur ein Mal in einem Set vorkommen.
Wir übergeben [1, 1, 2, 3, 4]
mit einer doppelten 1
. Da wir keine doppelten Werte in einem Set haben können wird eine 1
entfernt. Das Ergebnis ist {1, 2, 3, 4}
.
// counter.js
let counter = 10;
export default counter;
// index.js
import myCounter from "./counter";
myCounter += 1;
console.log(myCounter);
- A:
10
- B:
11
- C:
Error
- D:
NaN
Antwort
Ein importiertes Modul ist read-only, was bedeutet, dass importierte Module nicht geändert werden können. Nur das Modul, welches diese exportiert kann deren Wert ändern.
Wenn wir also den Wert von myCounter
erhöhen bekommen wir den Fehler myCounter is read-only and cannot be modified
.
const name = "Lydia";
age = 21;
console.log(delete name);
console.log(delete age);
- A:
false
,true
- B:
"Lydia"
,21
- C:
true
,true
- D:
undefined
,undefined
Antwort
Der delete
Operator gibt einen Boolean Wert zurück: true
bei erfolgreichem entfernen, oder andernfalls false
. Variablen, die mit var
, let
oder const
deklariert werden, können andererseits nicht mit delete
entfernt werden.
Der Wert von name
wurde mit const
deklariert, weshalb delete
nicht möglich ist und false
zurückgegeben wird. Als wir age
den Wert 21
zugewiesen haben, haben wir eine Property age
zum globalen Objekt hinzugefügt. Diese Properties kann man mit delete
entfernen, sodass delete age
true
zurückgibt.
const numbers = [1, 2, 3, 4, 5];
const [y] = numbers;
console.log(y);
- A:
[[1, 2, 3, 4, 5]]
- B:
[1, 2, 3, 4, 5]
- C:
1
- D:
[1]
Antwort
Wir können durch Destructuring Werte aus Arrays oder Properties aus Objekten entpacken. Zum Beispiel:
[a, b] = [1, 2];
Der Wert von a
ist jetzt 1
und der Wert von b
ist jetzt 2
. Was wir in der Frage eigentlich getan haben ist:
[y] = [1, 2, 3, 4, 5];
Das bedeutet, dass der Wert von y
gleich des ersten Wertes im Array ist, sprich der Zahl 1
entspricht. Wenn wir y
loggen bekommen wir 1
ausgegeben.
const user = { name: "Lydia", age: 21 };
const admin = { admin: true, ...user };
console.log(admin);
- A:
{ admin: true, user: { name: "Lydia", age: 21 } }
- B:
{ admin: true, name: "Lydia", age: 21 }
- C:
{ admin: true, user: ["Lydia", 21] }
- D:
{ admin: true }
Antwort
Es ist möglich Objekte mit dem Spread Operator ...
zu verbinden. Dieser erstellt Kopien der Key/Value Paare eines Objektes und fügt diese dem anderen Objekt hinzu. In diesem Fall wird eine Kopie des user
Objekts erstellt und dem admin
Objekt zugewiesen. Das admin
Objekt beinhaltet nun die kopierten Key/Value Paare, sodass das Ergebnis { admin: true, name: "Lydia", age: 21 }
ist.
const person = { name: "Lydia" };
Object.defineProperty(person, "age", { value: 21 });
console.log(person);
console.log(Object.keys(person));
- A:
{ name: "Lydia", age: 21 }
,["name", "age"]
- B:
{ name: "Lydia", age: 21 }
,["name"]
- C:
{ name: "Lydia"}
,["name", "age"]
- D:
{ name: "Lydia"}
,["age"]
Antwort
Mit der defineProperty
Methode können wir neue Properties zu einem Objekt hinzufügen oder bestehende modifizieren. Wenn wir mit der defineProperty
Methode Properties einem Objekt hinzufügen, sind diese standardmäßig nicht zählbar. Die Object.keys
Methode gibt alle zählbaren Property Namen eines Objektes zurück, in diesem Fall nur "name"
.
Properties, die mit defineProperty
erstellt wurden sind standardmäßig unveränderbar. Man kann dieses Verhalten mit den writable
, configurable
und enumerable
Properties verändern. Auf diese Art gibt die defineProperty
Methode mehr Kontrolle über die Properties, die einem Objekt hinzugefügt werden.
const settings = {
username: "lydiahallie",
level: 19,
health: 90
};
const data = JSON.stringify(settings, ["level", "health"]);
console.log(data);
- A:
"{"level":19, "health":90}"
- B:
"{"username": "lydiahallie"}"
- C:
"["level", "health"]"
- D:
"{"username": "lydiahallie", "level":19, "health":90}"
Antwort
Das zweite Argument von JSON.stringify
ist ein Replacer. Der Replacer kann entweder eine Funktion oder ein Array sein und gibt uns Kontrolle darüber, wie die Werte in Strings umgewandelt werden sollen.
Wenn der Replacer ein Array ist, werden nur die Properties dem JSON String hinzugefügt, die in dem Array aufgeführt sind. In diesem Fall sind das nur "level"
und "health"
. "username"
ist ausgeschlossen. data
ist jetzt gleich "{"level":19, "health":90}"
.
Wenn der Replacer eine Funktion ist, so wird diese Funktion für jede Property im Objekt aufgerufen, die in Strings umgewandelt wird. Der Wert, den die Funktion zurückgibt, ist der Wert der Property, die dem JSON String hinzugefügt wird. Ist der Wert undefined
, so wird die Property ausgeschlossen.
let num = 10;
const increaseNumber = () => num++;
const increasePassedNumber = number => number++;
const num1 = increaseNumber();
const num2 = increasePassedNumber(num1);
console.log(num1);
console.log(num2);
- A:
10
,10
- B:
10
,11
- C:
11
,11
- D:
11
,12
Antwort
Der unäre Operator ++
gibt zuerst den Wert des Operanden aus und erhöht danach den Wert des Operanden. Der Wert num1
ist 10
, da increaseNumber
zuerst den Wert von num1
(10
) ausgibt und ihn danach erhöht.
num2
ist gleich 10
, da wir num1
increasePassedNumber
zugewiesen haben. number
ist gleich 10
(der Wert von num1
). Der unäre Operator ++
gibt erneut zuerst den Wert des Operanden aus und erhöht danach den Wert. Der Wert von number
ist 10
, sodass num2
ebenfalls 10
ist.
const value = { number: 10 };
const multiply = (x = { ...value }) => {
console.log((x.number *= 2));
};
multiply();
multiply();
multiply(value);
multiply(value);
- A:
20
,40
,80
,160
- B:
20
,40
,20
,40
- C:
20
,20
,20
,40
- D:
NaN
,NaN
,20
,40
Antwort
In ES6 können wir Parameter mit einem Standardwert initialisieren. Der Wert des Parameters wird als Standard gesetzt, wenn kein anderer Wert übergeben wird oder der Wert des Parameters "undefined"
ist. In diesem Fall verteilen wir die Properties von value
in einem neuen Objekt, sodass x
den Standardwert { number: 10 }
bekommt.
Das Standard Argument wird beim Aufruf evaluiert. Jedes Mal, wenn wir die Funktion aufrufen, wird ein neues Objekt erstellt. Wir rufen die multiply
Funktion die ersten beiden Male auf ohne einen Wert zu übergeben: x
hat daher den Standardwert { number: 10 }
. Wir loggen dann den multiplizierten Wert davon, sodass wir 20
bekommen.
Beim dritten Mal wird die multiply
Funktion mit einem Argument für value
aufgerufen. Der *=
Operator ist kurz für x.number = x.number * 2
: wir ändern den Wert von x.number
und loggen den multiplizierten Wert 20
.
Beim vierten Mal übergeben wir wieder eine value
. x.number
wurde zuvor in 20
geändert, sodass x.number *= 2
jetzt 40
loggt.
[1, 2, 3, 4].reduce((x, y) => console.log(x, y));
- A:
1
2
und3
3
und6
4
- B:
1
2
und2
3
und3
4
- C:
1
undefined
und2
undefined
und3
undefined
und4
undefined
- D:
1
2
undundefined
3
undundefined
4
Antwort
Das erste Argument, welches die reduce
Methode erhält ist der Akkumulator x
. Das zweite Argument ist der aktuelle Wert, y
. Durch die reduce
Methode führen wir eine Callback Funktion an jedem Element des Arrays aus, was im Endeffekt einen einzelnen Wert ausgibt.
In diesem Beispiel geben wir nicht irgendwelche Werte aus, sondern loggen einfach nur den Akkumulator und den momentanen Wert.
Der Wert des Akkumulators ist gleich dem vorhergehenden Wert der Callback Funktion. Wenn wir initialValue
nicht an die reduce
Methode übergeben bleibt der Akkumulator gleich dem ersten Element des ersten Calls.
Beim ersten Call ist der Akkumulator (x
) gleich 1
und der aktuelle Wert (y
) ist 2
. Da wir in der Callback Funktion bleiben loggen wir den Akkumulator und den aktuellen Wert: 1
und 2
.
Wenn wir keinen Wert einer Funktion ausgeben wird undefined
ausgegeben. Beim nächsten Call ist der Akkumulator daher undefined
und der aktuelle Wert ist 3
. undefined
und 3
werden geloggt.
Beim vierten Call geben wir wieder nichts aus, sodass der Akkumulator wieder undefined
ist und der aktuelle Wert 4
. undefined
und 4
werden geloggt.
class Dog {
constructor(name) {
this.name = name;
}
};
class Labrador extends Dog {
// 1
constructor(name, size) {
this.size = size;
}
// 2
constructor(name, size) {
super(name);
this.size = size;
}
// 3
constructor(size) {
super(name);
this.size = size;
}
// 4
constructor(name, size) {
this.name = name;
this.size = size;
}
};
- A: 1
- B: 2
- C: 3
- D: 4
Antwort
In einer abgeleiteten Klasse kann das this
Keyword nicht aufgerufen werden, bevor super
aufgerufen wurde. Wenn man das versucht wird ein ReferenceError ausgeworfen: 1 und 4 würden daher einen Referenz-Fehler ausgeben.
Mit dem super
Keyword können wir den Constructor der Elternklasse mit gegebenen Argumenten aufrufen. Der Constructor der Elternklasse erhält das name
Argument, sodass wir name
an super
übergeben müssen.
Die Dog
Klasse erhält zwei Argumente, name
da es Animal
erweitert und size
als extra Property der Dog
Klasse. Beide müssen an die Constructor Funktion von Dog
übergeben werden, was nur bei Constructor 2 richtig ist.
// index.js
console.log('running index.js);
import { sum } from './sum.js';
console.log(sum(1, 2));
// sum.js
console.log('running sum.js');
export const sum = (a, b) => a + b;
- A:
running index.js
,running sum.js
,3
- B:
running sum.js
,running index.js
,3
- C:
running sum.js
,3
,running index.js
- D:
running index.js
,undefined
,running sum.js
Antwort
Mit dem import
Keyword werden alle importierten Module vorgeparsed. Das bedeutet, dass importierte Module zuerst ausgeführt werden, der Code in der eigentlichen Datei wird danach ausgeführt.
Das ist der große Unterschied zwischen require()
in CommonJS und import
. Mit require()
können Dependencies bei Bedarf geladen werden, während der Code ausgeführt wird. Hätten wir require()
anstelle von import
verwendet, wäre running index.js
, running sum.js
, 3
in der Konsole geloggt worden.
console.log(Number(2) === Number(2))
console.log(Boolean(false) === Boolean(false))
console.log(Symbol('foo') === Symbol('foo'))
- A:
true
,true
,false
- B:
false
,true
,false
- C:
true
,false
,true
- D:
true
,true
,true
Antwort
Jedes Symbol ist eindeutig. Der Sinn des Argumentes, welches an das Symbol weitergegeben wird, ist dem Symbol eine Beschreibung zu geben. Der Wert des Symbols hängt nicht von diesem Argument ab. Beim vergleichen der Symbole werden zwei komplett neue Symbole erstellt: das erste Symbol('foo')
und das zweite Symbol('foo')
. Diese beiden Werte sind eindeutig und nicht identisch, weshalb Symbol('foo') === Symbol('foo')
false
ausgibt.
const name = "Lydia Hallie"
console.log(name.padStart(13))
console.log(name.padStart(2))
- A:
"Lydia Hallie"
,"Lydia Hallie"
- B:
" Lydia Hallie"
," Lydia Hallie"
("[13x whitespace]Lydia Hallie"
,"[2x whitespace]Lydia Hallie"
) - C:
" Lydia Hallie"
,"Lydia Hallie"
("[1x whitespace]Lydia Hallie"
,"Lydia Hallie"
) - D:
"Lydia Hallie"
,"Lyd"
,
Antwort
Mit der padStart
Methode können wir Padding am Anfang des Strings hinzufügen. Der Wert, der an die Methode übergeben wird ist die absolute Länge des Strings mit dem Padding. Der String "Lydia Hallie"
hat eine Länge von 12
. name.padStart(13)
fügt ein Leerzeichen am Anfang des Strings ein, weil 12 + 1 = 13 ist.
Falls der Wert, der an padStart
übergeben wurde kleiner ist, als die Länge des Arrays, so wird kein Padding hinzugefügt.
console.log("🥑" + "💻");
- A:
"🥑💻"
- B:
257548
- C: Ein String, der den Emoji Code beinhaltet
- D: Error
Antwort
Mit dem +
Operator können Strings zusammengesetzt werden. In diesem Fall werden die Strings "🥑"
und "💻"
zusammengesetzt, was "🥑💻"
ergibt.
function* startGame() {
const Antwort = yield "Do you love JavaScript?";
if (Antwort !== "Yes") {
return "Oh wow... Guess we're gone here";
}
return "JavaScript loves you back ❤️";
}
const game = startGame();
console.log(/* 1 */); // Do you love JavaScript?
console.log(/* 2 */); // JavaScript loves you back ❤️
- A:
game.next("Yes").value
undgame.next().value
- B:
game.next.value("Yes")
undgame.next.value()
- C:
game.next().value
undgame.next("Yes").value
- D:
game.next.value()
undgame.next.value("Yes")
Antwort
Eine Generator Funktion pausiert die Ausführung, wenn das yield
Keyword vorliegt. Zuerst müssen wir den String "Do you love JavaScript?" abwarten, was mit game.next().value
möglich ist.
Jede Zeile wird ausgeführt, bis das erste yield
Keyword auftritt. Da auf der ersten Zeile ein yield
in der Funktion vorliegt wird die Ausführung damit angehalten. Das bedeutet, dass die Variable Antwort
noch nicht definiert wurde.
Wenn wir game.next("Yes").value
aufrufen wird das vorhergehende yield
durch den Wert des Parameters ersetzt, der an next()
übergeben wird - "Yes"
in diesem Fall. Der Wert der Variable Antwort
ist jetzt gleich "Yes"
. Das if-Statement gibt false
aus und JavaScript loves you back ❤️
wird geloggt.
console.log(String.raw`Hello\nworld`);
- A:
Hello world!
- B:
Hello
world
- C:
Hello\nworld
- D:
Hello\n
world
Antwort
String.raw
gibt einen String aus, in dem die Escapes (\n
, \v
, \t
etc.) ignoriert werden! Backslashes sind problematisch, weil man mit sowas in der Art rechnen muss:
const path = `C:\Documents\Projects\table.html`
Das würde dann wiefolgt gerendert werden:
"C:DocumentsProjects able.html"
Mit String.raw
werden diese ignoriert und das Ergebnis ist:
C:\Documents\Projects\table.html
In unserem Fall ist das Ergebnis Hello\nworld
, was geloggt wird.
async function getData() {
return await Promise.resolve("I made it!");
}
const data = getData();
console.log(data);
- A:
"I made it!"
- B:
Promise {<resolved>: "I made it!"}
- C:
Promise {<pending>}
- D:
undefined
Antwort
Eine async
Funktion gibt immer ein Promise zurück. Mit await
wird das Ergebnis des Promises abgewartet und ein ausstehendes Promise wird ausgegeben, wenn wir getData()
aufrufen um data
gleich zu setzen.
Wenn wir auf den finalen Wert "I made it"
zugreifen wollen, nutzen wir die .then()
Methode an data
:
data.then(res => console.log(res))
Das hätte "I made it!"
ausgegeben.
function addToList(item, list) {
return list.push(item);
}
const result = addToList("apple", ["banana"]);
console.log(result);
- A:
['apple', 'banana']
- B:
2
- C:
true
- D:
undefined
Antwort
Die .push()
Methode gibt die Länge des Arrays aus! Das Array beinhaltete zuerst ein einziges Element ("banana"
) und hatte eine Länge von 1
. Nachdem wir "apple"
hinzugefügt haben beinhaltet das Array zwei Elemente und hat eine Länge von 2
. Das wird letztlich von der addToList
Funktion ausgegeben.
Die push
Methode verändert das ursprüngliche Array. Wenn wir das Array der Funktion anstelle der Länge des Arrays ausgeben möchten, hätten wir list
ausgeben müssen.
const box = { x: 10, y: 20 };
Object.freeze(box);
const shape = box;
shape.x = 100;
console.log(shape);
- A:
{ x: 100, y: 20 }
- B:
{ x: 10, y: 20 }
- C:
{ x: 100 }
- D:
ReferenceError
Antwort
Object.freeze
macht es unmöglich das Objekt zu verändern (hinzufügen, entfernen, verändern), es sei denn der Wert ist ein weiteres Objekt.
Wenn wir die Variable shape
erstellen und gleich dem eingefrorenen Objekt box
setzen, ist shape
ebenso eingefroren. Man kann mit Object.isFrozen
prüfen, ob ein Objekt eingefroren ist.
In unserem Fall gibt Object.isFrozen(shape)
true
zurück, da die Variable shape
eine Referenz zu einem eingefrorenen Objekt ist.
Da shape
eingefroren ist und der Wert von x
kein Objekt ist, können wir den Wert von x
nicht verändern. x
ist immernoch gleich 10
und { x: 10, y: 20 }
wird geloggt.
const { name: myName } = { name: "Lydia" };
console.log(name);
- A:
"Lydia"
- B:
"myName"
- C:
undefined
- D:
ReferenceError
Antwort
Wenn wir die Property name
aus dem Objekt auf der rechten Seite destructuren, weisen wir den Wert einer neuen Variable myName
zu.
Mit { name: myName }
sagen wir JavaScript, dass wir eine neue Variable mit dem Namen myName
erstellen möchten und den Wert von name
zuweisen.
Da name
nicht definiert ist, wird ein ReferenceError ausgeworfen.
function sum(a, b) {
return a + b;
}
- A: Ja
- B: Nein
Antwort
Eine pure Funktion ist eine Funktion, die immer das gleiche Ergebnis zurück gibt, wenn die gleichen Argumente eingegeben werden.
Die sum
Funktion gibt daher immer das gleiche Ergebnis aus. Wenn wir 1
und 2
eingeben wird immer 3
ausgegeben. Wenn wir 5
und 10
eingeben wird immer 15
ausgegeben usw. Das ist die Definition einer puren Funktion.
const add = () => {
const cache = {};
return num => {
if (num in cache) {
return `From cache! ${cache[num]}`;
} else {
const result = num + 10;
cache[num] = result;
return `Calculated! ${result}`;
}
};
};
const addFunction = add();
console.log(addFunction(10));
console.log(addFunction(10));
console.log(addFunction(5 * 2));
- A:
Calculated! 20
Calculated! 20
Calculated! 20
- B:
Calculated! 20
From cache! 20
Calculated! 20
- C:
Calculated! 20
From cache! 20
From cache! 20
- D:
Calculated! 20
From cache! 20
Error
Antwort
Die add
Funktion ist memoized. Mit Memoization können wir Ergebnisse einer Funktion cachen, um die Performance zu beschleunigen. In diesem Fall erstellen wir ein cache
Objekt, welches die zuvor ausgegebenen Werte speichert.
Wenn wir die addFunction
Funktion erneut mit den gleichen Argumenten aufrufen wird zuerst geprüft, ob der Wert bereits im Cache vorhanden sind. Ist das der Fall, so wird der Cache diesen Wert ausgeben und damit Ausführzeit sparen. Wenn der Wert nicht gecached ist wird der neue Wert berechnet und danach im Cache gespeichert.
Wir rufen die addFunction
Funktion drei mal mit dem gleichen Wert auf: bei der ersten Ausführung. ist der Wert der Funktion 10
nicht im Cache. Die Kondition des if-Statements num in cache
gibt false
aus und der else Block wird ausgeführt: Calculated! 20
wird geloggt und der Wert des Ergebnisses wird dem Cache Objekt hinzugefügt. cache
sieht jetzt wiefolgt aus: { 10: 20 }
.
Bei der zweiten Ausführung beinhaltet das cache
Objekt den Wert 10
. Die Kondition des if-Statements num in cache
gibt true
aus und 'From cache! 20'
wird geloggt.
Beim dritten Mal geben wir 5 * 2
als Argument in die Funktion ein, was 10
ergibt. Das cache
Objekt beinhaltet den Wert 10
und das if-Statement num in cache
gibt wieder true
aus und 'From cache! 20'
wird geloggt.
const myLifeSummedUp = ["☕", "💻", "🍷", "🍫"]
for (let item in myLifeSummedUp) {
console.log(item)
}
for (let item of myLifeSummedUp) {
console.log(item)
}
- A:
0
1
2
3
und"☕"
"💻"
"🍷"
"🍫"
- B:
"☕"
"💻"
"🍷"
"🍫"
und"☕"
"💻"
"🍷"
"🍫"
- C:
"☕"
"💻"
"🍷"
"🍫"
und0
1
2
3
- D:
0
1
2
3
und{0: "☕", 1: "💻", 2: "🍷", 3: "🍫"}
Antwort
Mit einer for-in Schleife können wir über zählbare Properties iterieren. In einem Array sind die zählbaren Properties die "Keys" des Array Elements, sprich deren Indexe. Ein Array könnte man also wiefolgt sehen:
{0: "☕", 1: "💻", 2: "🍷", 3: "🍫"}
Daher werden die zählbaren Properties 0
1
2
3
geloggt.
Mit einer for-of Schleife können wir über wiederholbare Elemente iterieren. Ein Array ist wiederholbar. Wenn wir also über das Array iterieren, ist die Variable "item" gleich dem Element, welches momentan iteriert wird: "☕"
"💻"
"🍷"
"🍫"
wird geloggt.
const list = [1 + 2, 1 * 2, 1 / 2]
console.log(list)
- A:
["1 + 2", "1 * 2", "1 / 2"]
- B:
["12", 2, 0.5]
- C:
[3, 2, 0.5]
- D:
[1, 1, 1]
Antwort
Array Elemente können jeden Wert halten: Nummern, Strings, Objekte, andere Arrays, null, Booleans, undefined und andere Expressions wie Funktionen, Berechnungen oder ein Datum.
Das Element ist gleich dem ausgegebenen Wert. 1 + 2
ergibt 3
, 1 * 2
ergibt 2
, und 1 / 2
ergibt 0.5
.
function sayHi(name) {
return `Hi there, ${name}`
}
console.log(sayHi())
- A:
Hi there,
- B:
Hi there, undefined
- C:
Hi there, null
- D:
ReferenceError
Antwort
Standardmäßig haben Argumente den Wert undefined
, es sei denn der Funktion wurde ein Wert zugewiesen. In diesem Fall haben wir dem name
Argument keinen Wert zugewiesen, weshalb name
undefined
ist.
In ES6 können wir diesen Standardwert undefined
mit Standard Parametern überschreiben, zum Beispiel:
function sayHi(name = "Lydia") { ... }
In diesem Fall, falls wir kein Argument oder undefined
eingeben ist name
immer Lydia
.
var status = "😎"
setTimeout(() => {
const status = "😍"
const data = {
status: "🥑",
getStatus() {
return this.status
}
}
console.log(data.getStatus())
console.log(data.getStatus.call(this))
}, 0)
- A:
"🥑"
und"😍"
- B:
"🥑"
und"😎"
- C:
"😍"
und"😎"
- D:
"😎"
und"😎"
Antwort
Der Wert des this
Keywords hängt davon ab, wo es verwendet wird. In einer Methode, wie getStatus
bezieht sich das this
Keyword auf das Objekt, zu dem die Methode gehört. Die Methode gehört zum data
Objekt, sodass this
sich auf das data
Objekt bezieht. Wenn wir this.status
loggen wird die status
Property des data
Objekts geloggt, was "🥑"
ist.
Mit der call
Methode können wir das Objekt, auf welches sich das this
Keyword bezieht ändern. In Funktionen bezieht sich this
auf das Objekt, zu dem die Funktion gehört. Wir erklären die setTimeout
Funktion im globalen Objekt, sodass sich this
in setTimeout
auf das globale Objekt bezieht. Im globalen Objekt gibt es status mit dem Wert "😎"
, was geloggt wird.
const person = {
name: "Lydia",
age: 21
}
let city = person.city
city = "Amsterdam"
console.log(person)
- A:
{ name: "Lydia", age: 21 }
- B:
{ name: "Lydia", age: 21, city: "Amsterdam" }
- C:
{ name: "Lydia", age: 21, city: undefined }
- D:
"Amsterdam"
Antwort
Wir setzen die Variable city
gleich dem Wert der Property city
am person
Objekt. Da am person
Objekt keine Property namens city
existiert wird der Wert gleich undefined
gesetzt.
Da wir nicht das person
Objekt selbst referenzieren, sondern einfach die Variable city
gleich dem aktuellen Wert von city
am person
Objekt setzen bleibt dieses undefined
.
Dann setzen wir city
gleich dem String "Amsterdam"
. Das verändert aber nicht das person
Objekt, da es keine Referenz dazu am Objekt gibt.
Wenn wir person
loggen bekommen wir daher das unveränderte Objekt angezeigt.
function checkAge(age) {
if (age < 18) {
const message = "Sorry, you're too young."
} else {
const message = "Yay! You're old enough!"
}
return message
}
console.log(checkAge(21))
- A:
"Sorry, you're too young."
- B:
"Yay! You're old enough!"
- C:
ReferenceError
- D:
undefined
Antwort
Variablen mit dem const
und let
Keyword sind block-scoped. Ein Block ist alles zwischen geschweiften Klammern ({ }
), in diesem Fall die geschweiften Klammern des if/else Statements. Es ist nicht möglich eine solche Variable außerhalb des Blocks in dem sie erklärt wurde aufzurufen, daher wird ein ReferenceError ausgegeben.
fetch('https://www.website.com/api/user/1')
.then(res => res.json())
.then(res => console.log(res))
- A: Das Ergebnis der
fetch
Methode. - B: Das Ergebnis des zweiten Aufrufs der
fetch
Methode. - C: Das Ergebnis des Callbacks im vorhergehenden
.then()
. - D: Immer
undefined
.
Antwort
Der Wert von res
im zweiten .then
ist gleich dem ausgegebenen Wert des vorhergehenden .then
. Man kann soviele .then
s aneinander reihen, wie man möchte und der Wert wird immer an den nächsten Handler übergeben.
86. Wie können wir hasName
gleich true
setzen, vorausgesetzt wir können true
nicht als Argument übergeben?
function getName(name) {
const hasName = //
}
- A:
!!name
- B:
name
- C:
new Boolean(name)
- D:
name.length
Antwort
Mit !!name
können wir feststellen, ob name
truthy oder falsey ist. Ist name
truthy, so würde !name
false
ausgeben. !false
(das Gleiche wie !!name
) ergibt true
.
Wenn wir hasName
gleich name
setzen, so beinhaltet hasName
den Wert von name
, nicht den Boolean Wert true
.
new Boolean(true)
gibt einen Objekt Wrapper aus, nicht ein Boolean ansich.
name.length
gibt die Länge des Arguments aus, nicht den Boolean Wert.
console.log("I want pizza"[0])
- A:
"""
- B:
"I"
- C:
SyntaxError
- D:
undefined
Antwort
Um ein Zeichen an einer bestimmten Stelle eines Strings zu bekommen kann man Bracket Notation verwenden. Das erste Zeichen in einem String hat den Index 0, usw. In diesem Fall möchten wir das Zeichen mit dem Index 0, was das Zeichen "I"
loggt.
Diese Methode funktioniert nicht in IE7 und davor. Hier muss .charAt()
verwendet werden.
function sum(num1, num2 = num1) {
console.log(num1 + num2)
}
sum(10)
- A:
NaN
- B:
20
- C:
ReferenceError
- D:
undefined
Antwort
Man kann den Wert eines Standard Parameters gleich einem anderen Parameter in der Funktion setzen, sofern diese vor dem Standard Parameter definiert wurden. Wir übergeben den Wert 10
an die sum
Funktion. Wenn die sum
Funktion nur ein Argument übergeben bekommt bedeutet das, dass der Wert für num2
nicht gesetzt wurde und der Wert von num1
ist gleich dem Wert 10
. Der Standardwert von num2
ist gleich dem Wert von num1
, sprich 10
. num1 + num2
gibt 20
aus.
Wenn man den Wert des Standard Paramenters gleich dem Parameter setztm der danach definiert wurde, bekommen wir einen Fehler ausgegeben, da der Wert noch nicht initialisiert wurde.
// module.js
export default () => "Hello world"
export const name = "Lydia"
// index.js
import * as data from "./module"
console.log(data)
- A:
{ default: function default(), name: "Lydia" }
- B:
{ default: function default() }
- C:
{ default: "Hello world", name: "Lydia" }
- D: Globales Objekt von
module.js
Antwort
Mit import * as name
importieren wir alle Exporte der module.js
in index.js
als data
. In der Datei module.js
haben wir zwei Exporte: den Standard Export und einen benannten Export. Der Standard Export ist eine Funktion, die "Hello World"
ausgibt und der benannte Export ist eine Variable namens name
mit dem Wert "Lydia"
.
Das data
Objekt hat eine Standard Property für alle Standard Exporte, andere Properties haben die Namen des benannten Exports und der entsprechenden Werte.
class Person {
constructor(name) {
this.name = name
}
}
const member = new Person("John")
console.log(typeof member)
- A:
"class"
- B:
"function"
- C:
"object"
- D:
"string"
Antwort
Klassen sind syntaktischer Zucker für Funktionskontruktoren. Das Equivalent der Person
Klasse als Funktionskonstruktor wäre:
function Person() {
this.name = name
}
Das Aufrufen eines Funktionskonstruktors mit new
hat zur Folge, dass eine Instanz von Person
erstellt wird. typeof
gibt "object"
für die instanz aus. typeof member
gibt "object"
aus.
let newList = [1, 2, 3].push(4)
console.log(newList.push(5))
- A:
[1, 2, 3, 4, 5]
- B:
[1, 2, 3, 5]
- C:
[1, 2, 3, 4]
- D:
Error
Antwort
Die .push
Methode gibt die neue Länge des Arrays aus, nicht die Länge des Arrays selbst. Wenn wir newList
gleich [1, 2, 3].push(4)
setzen, setzen wir newList
auch gleich der Länge des Arrays: 4
.
Dann versuchen wir die .push
Methode auf newList
anzuwenden. Da newList
den numerischen Wert 4
beinhaltet können wir die .push
Methode nicht anwenden: ein TypeError wird ausgegeben.
function giveLydiaPizza() {
return "Here is pizza!"
}
const giveLydiaChocolate = () => "Here's chocolate... now go hit the gym already."
console.log(giveLydiaPizza.prototype)
console.log(giveLydiaChocolate.prototype)
- A:
{ constructor: ...}
{ constructor: ...}
- B:
{}
{ constructor: ...}
- C:
{ constructor: ...}
{}
- D:
{ constructor: ...}
undefined
Antwort
Reguläre Funktionen wie giveLydiaPizza
haben eine prototype
Property, die ein Objekt (Prototype Object) mit einem constructor
ist. Arrow Funktionen dagegen (wie giveLydiaChocolate
) haben keinen prototype
. undefined
wird ausgegeben, wenn wir versuchen den prototype
mit giveLydiaChocolate.prototype
aufzurufen.
const person = {
name: "Lydia",
age: 21
}
for (const [x, y] of Object.entries(person)) {
console.log(x, y)
}
- A:
name
Lydia
undage
21
- B:
["name", "Lydia"]
und["age", 21]
- C:
["name", "age"]
undundefined
- D:
Error
Antwort
Object.entries(person)
gibt ein Array mit verschachtelten Arrays der Keys aus:
[ [ 'name', 'Lydia' ], [ 'age', 21 ] ]
Mit der for-of
Schleife iterieren wir über jedes Element in dem Array, in diesem Fall die verschachtelten Arrays. Wir können die verschachtelten Arrays mit const [x, y]
in der for-of Schleife destrukturieren. x
ist gleich dem ersten Element, y
ist gleich dem zweiten Element in dem verschachtelten Array.
Das erste verschachtelte Array ist [ "name", "Lydia" ]
. x
ist gleich "name"
und y
gleich "Lydia"
, was geloggt wird.
Das zweite verschachtelte Array ist [ "age", 21 ]
. x
ist gleich "age"
und y
ist gleich 21
, was geloggt wird.
function getItems(fruitList, ...args, favoriteFruit) {
return [...fruitList, ...args, favoriteFruit]
}
getItems(["banana", "apple"], "pear", "orange")
- A:
["banana", "apple", "pear", "orange"]
- B:
[["banana", "apple"], "pear", "orange"]
- C:
["banana", "apple", ["pear"], "orange"]
- D:
SyntaxError
Antwort
...args
ist ein Rest-Parameter. Der Wert des Rest-Parameters ist ein Array mit allen weiteren Argumenten und kann nur der letzte Parameter sein! In diesem Beispiel war der Rest-Parameter das zweite Argument, was nicht möglich ist und daher einen Syntax Error ausgibt.
function getItems(fruitList, favoriteFruit, ...args) {
return [...fruitList, ...args, favoriteFruit]
}
getItems(["banana", "apple"], "pear", "orange")
Dieses Beispiel würde funktionieren und [ 'banana', 'apple', 'orange', 'pear' ]
ausgeben.
function nums(a, b) {
if
(a > b)
console.log('a is bigger')
else
console.log('b is bigger')
return
a + b
}
console.log(nums(4, 2))
console.log(nums(1, 2))
- A:
a is bigger
,6
undb is bigger
,3
- B:
a is bigger
,undefined
undb is bigger
,undefined
- C:
undefined
undundefined
- D:
SyntaxError
Antwort
In JavaScript muss das Semikolon nicht explizit gesetzt werden, allerdings setzt die JavaScript Engine Semikolons nach Statements. Diesen Vorgang nennt man automatische Semikolonsetzung. Ein Statement ist zum Beispiel eine Variable oder ein Keyword wie throw
, return
, break
, usw.
In unserem Beispiel haben wir ein return
Statement gefolgt von einem anderen Wert a + b
auf der nächsten Zeile. Da es eine neue Zeile ist, weiß JavaScript nicht, dass das der Wert ist, den wir eigentlich ausgeben wollten. Stattdessen wird automatisch ein Semikolon nach return
gesetzt, was man wiefolgt lesen kann:
return;
a + b
Das bedeutet, dass a + b
nie erreicht wird, da die Funktion auf der Zeile davor mit dem return
Keyword endet. Wenn wie hier kein Wert ausgegeben wird, gibt die Funktion undefined
aus.
Bedenke: Semikolons werden nicht automatisch nach if/else
Statements gesetzt!
class Person {
constructor() {
this.name = "Lydia"
}
}
Person = class AnotherPerson {
constructor() {
this.name = "Sarah"
}
}
const member = new Person()
console.log(member.name)
- A:
"Lydia"
- B:
"Sarah"
- C:
Error: cannot redeclare Person
- D:
SyntaxError
Antwort
Wir können Klassen gleich anderen Klassen oder Funktions Konstruktoren setzen. In diesem Beispiel setzen wir Person
gleich AnotherPerson
. Der Name in diesem Konstruktor ist Sarah
, sodass die name-Property der neuen Person
Instanz member
gleich "Sarah"
ist.
const info = {
[Symbol('a')]: 'b'
}
console.log(info)
console.log(Object.keys(info))
- A:
{Symbol('a'): 'b'}
und["{Symbol('a')"]
- B:
{}
und[]
- C:
{ a: "b" }
und["a"]
- D:
{Symbol('a'): 'b'}
und[]
Antwort
Ein Symbol ist nicht zählbar. Die Object.keys
Methode gibt alle zählbaren Key Properties eines Objekts aus. Das Symbol ist nicht sichtbar, sodass ein leeres Array ausgegeben wird. Wenn wir das gesamte Objekt loggen sind alle Properties sichtbar, auch nicht zählbare.
Das ist einer der vielen Vorteile eines Symbols: nebem einem einzigartigen Wert (welcher verhindert, dass versehentlich zwei Objekte gleiche Namen haben, zum Beispiel wenn wir mit verschiedenen Libraries arbeiten) können Properties von Objekten auf diese Art versteckt werden.
Bedenke: Man kann die Symbole dennoch mit der Object.getOwnPropertySymbols()
Methode einsehen.
const getList = ([x, ...y]) => [x, y]
const getUser = user => { name: user.name, age: user.age }
const list = [1, 2, 3, 4]
const user = { name: "Lydia", age: 21 }
console.log(getList(list))
console.log(getUser(user))
- A:
[1, [2, 3, 4]]
undundefined
- B:
[1, [2, 3, 4]]
und{ name: "Lydia", age: 21 }
- C:
[1, 2, 3, 4]
und{ name: "Lydia", age: 21 }
- D:
Error
und{ name: "Lydia", age: 21 }
Antwort
Die getList
Funktion bekommt ein Array als Argument zugewiesen. Zwischen den Klammern der getList
Funktion wird das Array direkt destrukturiert. Man könnte das auch wiefolgt sehen:
[x, ...y] = [1, 2, 3, 4]
Mit dem Rest Parameter ...y
packen wir alle übrigen Argumente in ein Array. Die übrigen Argumente sind in dem Fall 2
, 3
und 4
. Der Wert von y
ist ein Array mit den restlichen Parametern. Der Wert von x
ist gleich 1
sodass [1, [2, 3, 4]]
geloggt wird.
Die getUser
Funktion bekommt ein Objekt zugewiesen. Bei Arrow Funktionen müssen wir keine geschweiften Klammern verwenden, wenn wir nur einen Wert ausgeben. Wenn wir aber ein Objekt von einer Arrow Funktion ausgeben lassen möchten, so muss dieses zwischen Klammern stehen, ansonsten wird nichts ausgegeben. Die folgende Funktion hätte ein Objekt ausgegeben:
const getUser = user => ({ name: user.name, age: user.age })
Da kein Wert ausgegeben wird, gibt die Funktion undefined
aus.
const name = "Lydia"
console.log(name())
- A:
SyntaxError
- B:
ReferenceError
- C:
TypeError
- D:
undefined
Antwort
Die Variable name
beinhaltet einen String, welcher logischer Weise keine Funktion ist und daher nicht ausgeführt werden kann.
TypeErrors werden ausgeworfen, wenn ein Wert einen falschen Typ aufweist. JavaScript hat eine Funktion erwartet, da wir name
ausführen. Da es aber ein String war bekommen wir den TypeError: name is not a function!
SyntaxErrors werden ausgeworfen, wenn wir etwas schreiben, was kein gültiger JavaScript Code ist, zum Beispiel wenn wir uns vertippen und anstatt return
retrun
schreiben.
ReferenceErrors werden ausgeworfen, wenn JavaScript eine Referenz zu einem Wert nicht finden kann.
// 🎉✨ Das ist unsere 100. Frage! ✨🎉
const output = `${[] && 'Im'}possible!
You should${'' && `n't`} see a therapist after so much JavaScript lol`
- A:
possible! You should see a therapist after so much JavaScript lol
- B:
Impossible! You should see a therapist after so much JavaScript lol
- C:
possible! You shouldn't see a therapist after so much JavaScript lol
- D:
Impossible! You shouldn't see a therapist after so much JavaScript lol
Antwort
[]
ist ein "truthy" Wert. Mit dem &&
Operator geben wir den rechten Wert aus, wenn der linke truthy ist. In diesem Fall ist []
truthy, wodurch "Im'
ausgegeben wird.
""
ein ein "falsy" Wert. Wenn der linke Wert falsy ist wird nichts ausgegeben. In diesem Fall wird n't
nicht ausgegeben.
const one = (false || {} || null)
const two = (null || false || "")
const three = ([] || 0 || true)
console.log(one, two, three)
- A:
false
null
[]
- B:
null
""
true
- C:
{}
""
[]
- D:
null
null
true
Antwort
Mit dem ||
Operator geben wir den ersten truthy Operand aus. Wenn alle Werte falsy sind wird der letzte Operand ausgegeben.
(false || {} || null)
: das leere Objekt {}
ist truthy. Das ist der erste und einzige truthy Wert und wird daher ausgegeben. one
ist gleich {}
.
(null || false || "")
: alle Operanden sind falsy. Das bedeutet, dass der letzte Wert ""
ausgegeben wird. two
ist gleich ""
.
([] || 0 || "")
: das leere Array []
ist truthy. Das ist der erste truthy Wert, und wird daher ausgegeben. three
ist gleich []
.
const myPromise = () => Promise.resolve('I have resolved!')
function firstFunction() {
myPromise().then(res => console.log(res))
console.log('second')
}
async function secondFunction() {
console.log(await myPromise())
console.log('second')
}
- A:
I have resolved!
,second
undI have resolved!
,second
- B:
second
,I have resolved!
undsecond
,I have resolved!
- C:
I have resolved!
,second
undsecond
,I have resolved!
- D:
second
,I have resolved!
undI have resolved!
,second
Antwort
Mit einem Promise sagen wir Ich möchte diese Funktion ausführen, aber ich lege sie erstmal beiseite, weil sie eine Weile braucht. Erst wenn ein bestimmter Wert ausgegeben (oder rejected) wird und der Call Stack leer ist möchte ich den Wert nutzen.
Wir können auf den Wert mit .then()
oder await
in einer async
Funktion zugreifen, aber .then()
und await
unterscheiden sich in einem bestimmten Punkt.
In firstFunction
legen wir myPromise
beiseite, während die Funktion durchläuft, aber wir arbeiten anderen Code ab, hier console.log('second')
.
Dann wird die Funktion abgeschlossen und der String I have resolved
wird ausgegeben, nachdem sich der Call Stack geleert hat.
Mit dem await
Keyword in secondFunction
wird die Funktion gestoppt bis der Wert ausgegeben wurde, erst dann wird die nächste Zeile ausgeführt.
Das bedeutet, dass auf myPromise
gewartet und dann der Wert I have resolved
ausgegeben wird und erst dann wird die nächste Zeile ausgeführt und second
wird geloggt.
const set = new Set()
set.add(1)
set.add("Lydia")
set.add({ name: "Lydia" })
for (let item of set) {
console.log(item + 2)
}
- A:
3
,NaN
,NaN
- B:
3
,7
,NaN
- C:
3
,Lydia2
,[object Object]2
- D:
"12"
,Lydia2
,[object Object]2
Antwort
Der +
Operator wird nicht nur für numerische Werte verwendet, wir können mit ihm ebenso Strings zusammenfügen. Immer, wenn JavaScript merkt, dass mindestens ein Wert keine Nummer ist, wird ein String erstellt.
Der erste Wert ist 1
, was ein numerischer Wert ist. 1 + 2
ergibt die Zahl 3
.
Der zweite Wert hingegen ist der String "Lydia"
. "Lydia"
ist ein String und 2
ist eine Nummer: 2
wird in einem String umgewandelt. "Lydia"
und "2"
werden zusammengesetzt, was den String "Lydia2"
ausgibt.
{ name: "Lydia" }
ist ein Objekt. Weder eine Nummer, noch ein Objekt sind ein String, aber beide werden zu Strings konvertiert und "[object Object]"
wird ausgegeben. "[object Object]"
zusammengesetzt mit "2"
wird "[object Object]2"
.
Promise.resolve(5)
- A:
5
- B:
Promise {<pending>: 5}
- C:
Promise {<fulfilled>: 5}
- D:
Error
Antwort
Wir können jeden Wert an Promise.resolve
übergeben, es muss nicht unbedingt ein Promise sein. Die Methode selbst gibt ein Promise zurück, was einen Wert ausgibt (<fulfilled>
). Wenn man eine normale Funktion übergibt wird das Promise einen normalen Wert ausgeben. Wenn ein Promise übergeben wird so wird ein Promise gelöst und der Wert des gelösten Promises ausgegeben.
In diesem Fall haben wir nur die Zahl 5
übergeben und diese wird genauso ausgegeben: 5
.
function compareMembers(person1, person2 = person) {
if (person1 !== person2) {
console.log("Not the same!")
} else {
console.log("They are the same!")
}
}
const person = { name: "Lydia" }
compareMembers(person)
- A:
Not the same!
- B:
They are the same!
- C:
ReferenceError
- D:
SyntaxError
Antwort
Objekte werden durch eine Referenz übergeben. Wenn wir Objekte auf strikte Gleichheit (===
) prüfen, vergleichen wir nur deren Referenz.
Wir setzen den Standardwert für person2
gleich dem person
Objekt und übergeben dem person
Objekt den Wert von person1
.
Das bedeutet, dass beide Werte eine Referenz zum gleichen Ort im Speicher aufweisen und daher gleich sind.
Der Code im else
Statement wird aufgerufen und They are the same!
wird geloggt.
const colorConfig = {
red: true,
blue: false,
green: true,
black: true,
yellow: false,
}
const colors = ["pink", "red", "blue"]
console.log(colorConfig.colors[1])
- A:
true
- B:
false
- C:
undefined
- D:
TypeError
Antwort
In JavaScript gibt es zwei Wege auf Properties an Objekten zuzugreifen: Punkt-Notation oder Klammern-Notation. In diesem Beispiel nutzen wir Punkt-Notation (colorConfig.colors
) anstelle von Klammern-Notation (colorConfig["colors"]
).
Mit Punkt-Notation versucht JavaScript die Property am Objekt mit diesem exakten Namen zu finden. In unserem Beispiel colors
im colorConfig
Objekt. Da es keine Property colorConfig
gibt wird undefined
ausgegeben. Dann versuchen wir den Wert des ersten Elements mit [1]
aufzurufen, was an undefined
nicht möglich ist, wodurch wir TypeError: Cannot read property '1' of undefined
ausgegeben bekommen.
JavaScript interpretiert Statements. Wenn wir Klammern-Notation verwenden wird die erste Klammer [
gefunden und JavaScript sucht solange, bis eine schließende Klammer ]
gefunden wird. Erst dann wird das Statement interpretiert. Hätten wir colorConfig[colors[1]]
verwendet, wäre der Wert red
ausgegeben worden.
console.log('❤️' === '❤️')
- A:
true
- B:
false
Antwort
Emojis sind im Endeffekt nur Unicodes. Der Unicode für das Herz Emoji ist "U+2764 U+FE0F"
. Dieser ist immer gleich, für das selbe Emoji und daher wird true
ausgegeben.
const emojis = ['✨', '🥑', '😍']
emojis.map(x => x + '✨')
emojis.filter(x => x !== '🥑')
emojis.find(x => x !== '🥑')
emojis.reduce((acc, cur) => acc + '✨')
emojis.slice(1, 2, '✨')
emojis.splice(1, 2, '✨')
- A:
All of them
- B:
map
reduce
slice
splice
- C:
map
slice
splice
- D:
splice
Antwort
Mit der splice
Methode ändern wir das ursprüngliche Array durch löschen, ersetzen oder ergänzen von Elementen. In diesem Fall haben wir 2 Elemente vom Index 1 ('🥑'
und '😍'
) entfernt und ✨ stattdessen eingefügt.
map
, filter
und slice
geben ein neues Array aus, find
gibt ein Element aus und reduce
gibt einen neuen Wert aus.
const food = ['🍕', '🍫', '🥑', '🍔']
const info = { favoriteFood: food[0] }
info.favoriteFood = '🍝'
console.log(food)
- A:
['🍕', '🍫', '🥑', '🍔']
- B:
['🍝', '🍫', '🥑', '🍔']
- C:
['🍝', '🍕', '🍫', '🥑', '🍔']
- D:
ReferenceError
Antwort
In JavaScript interagieren primitive Datentypen (alles außer Objekte) anhand des Wertes. In diesem Beispiel setzen wir den Wert von favoriteFood
am info
Objekt gleich dem Wert des ersten Elements im food
Array, in dem Fall ein String mit dem Pizza Emoji ('🍕'
). Ein String ist ein primitiver Datentyp und agiert daher in JavaScript nach Referenz. (Siehe mein Blogpost für mehr Informationen)
Dann ändern wir den Wert von favoriteFood
am info
Objekt. Das food
Array hat sich nicht verändert, da der Wert von favoriteFood
nur eine Kopie des Wertes des ersten Elements im Array war und keine Referenz zum Element food[0]
im Speicher finden kann. Wenn wir also das Essen loggen ist es immernoch das ursprüngliche Array ['🍕', '🍫', '🥑', '🍔']
.
JSON.parse()
- A: Parsed JSON in einen JavaScript Wert
- B: Parsed ein JavaScript Objekt zu JSON
- C: Parsed jegliche JavaScript Werte zu JSON
- D: Parsed JSON zu jeglichem JavaScript Objekt
Antwort
Mit der JSON.parse()
Methode können wir einen JSON String zu einem JavaScript Wert umwandeln.
// Stringifying a number into valid JSON, then parsing the JSON string to a JavaScript value:
const jsonNumber = JSON.stringify(4) // '4'
JSON.parse(jsonNumber) // 4
// Stringifying an array value into valid JSON, then parsing the JSON string to a JavaScript value:
const jsonArray = JSON.stringify([1, 2, 3]) // '[1, 2, 3]'
JSON.parse(jsonArray) // [1, 2, 3]
// Stringifying an object into valid JSON, then parsing the JSON string to a JavaScript value:
const jsonArray = JSON.stringify({ name: "Lydia" }) // '{"name":"Lydia"}'
JSON.parse(jsonArray) // { name: 'Lydia' }
let name = 'Lydia'
function getName() {
console.log(name)
let name = 'Sarah'
}
getName()
- A: Lydia
- B: Sarah
- C:
undefined
- D:
ReferenceError
Antwort
Jede Funktion hat ihren eigenen Ausführungskontext (oder scope). Die getName
Funktion sucht zuerst in ihrem eigenen Kontext (scope) um zu sehen, ob sie den Wert name
finden kann. In diesem Fall beinhaltet die getName
Funktion ihre eigene Variable name
: wir setzen die Variable name
mit dem let
Keyword und dem Wert 'Sarah'
.
Variablen mit dem let
und const
Keyword werden gehoisted, aber entgegen var
werden diese nicht initialisiert. Sie sind nicht aufrufbar, bevor wir sie deklarieren (initialisieren). Das ist eine "vorübergehende tote Zone" (temporal dead zone). Wir bekommen einen ReferenceError
ausgegeben.
Hätten wir die name
Variable nicht innerhalb getName
deklariert, so hätte JavaScript außerhalb der Funktion in der Scope-Kette weitergesucht. Der äußere Scope beinhaltet ebenfalls eine Variable name
mit dem Wert 'Lydia'
. In diesem Fall wäre Lydia
geloggt worden.
let name = 'Lydia'
function getName() {
console.log(name)
}
getName() // Lydia
function* generatorOne() {
yield ['a', 'b', 'c'];
}
function* generatorTwo() {
yield* ['a', 'b', 'c'];
}
const one = generatorOne()
const two = generatorTwo()
console.log(one.next().value)
console.log(two.next().value)
- A:
a
anda
- B:
a
andundefined
- C:
['a', 'b', 'c']
anda
- D:
a
and['a', 'b', 'c']
Antwort
Mit dem yield
Keyword, halten wir Werte in einer Generator-Funktion. Mit dem yield*
Keyword können wir Werte einer anderen Generator-Funktion oder Objekte und Arrays halten.
In generatorOne
halten wir das gesamte Array ['a', 'b', 'c']
mit dem yield
Keyword. Der Wert von value
am Objekt gibt die next
Methode an one
(one.next().value
) aus, was dem gesamten Array entspricht: ['a', 'b', 'c']
.
console.log(one.next().value) // ['a', 'b', 'c']
console.log(one.next().value) // undefined
In generatorTwo
verwenden wir das yield*
Keyword. Das bedeutet, dass der erste gehaltene Wert von two
gleich dem ersten gehaltenen Wert ist. Das ist das Array ['a', 'b', 'c']
. Der erste gehaltene Wert ist a
, was ausgegeben wird.
console.log(two.next().value) // 'a'
console.log(two.next().value) // 'b'
console.log(two.next().value) // 'c'
console.log(two.next().value) // undefined
console.log(`${(x => x)('I love')} to program`)
- A:
I love to program
- B:
undefined to program
- C:
${(x => x)('I love') to program
- D:
TypeError
Antwort
Expressions innerhalb von Template Literals werden zuerst berechnet. Das bedeutet, dass der String den ausgegebenen Wert der Expression beinhaltet, hier die IIFE (immediately invoked Function) (x => x)('I love')
. Wir geben den Wert 'I love'
als Argument an die x => x
Arrow Funktion. x
ist gleich 'I love'
und wird ausgegeben. Das Ergebnis ist I love to program
.
let config = {
alert: setInterval(() => {
console.log('Alert!)
}, 1000)
}
config = null
- A: Die
setInterval
Callback Funktion wird nicht aufgerufen - B: Die
setInterval
Callback Funktion wird ein Mal aufgerufen - C: Die
setInterval
Callback Funktion wird weiterhin jede Sekunde aufgerufen - D: Wir haben
config.alert()
nie aufgerufen,config
istnull
Antwort
Wenn wir normalerweise Objekte gleich null
setzen, werden diese verworfen, weil keine Referenz mehr zu ihnen existiert. Da die Callback Funktion in setInterval
eine Arrow Funktion (und daher an config
gebunden) ist, hält die Callback Funktion immernoch eine Referenz zum config
Objekt. Solange eine Referenz besteht, wird das Objekt nicht verworfen und die setInterval
Funktion wird weiterhin alle 1000ms (1 Sekunde) aufgerufen.
const myMap = new Map()
const myFunc = () => 'greeting'
myMap.set(myFunc, 'Hello world!')
//1
myMap.get('greeting')
//2
myMap.get(myFunc)
//3
myMap.get(() => 'greeting'))
- A: 1
- B: 2
- C: 2 und 3
- D: Alle
Antwort
Beim Setzen eines Key/Wert Paars mit der set
Methode wird der Key als erstes Argument an die set
Funktion übergeben und der Wert wird als zweites Argument eingegeben. Der Key ist die Funktion () => 'greeting'
und der Wert ist 'Hello world'
. myMap
ist jetzt { () => 'greeting' => 'Hello world!' }
.
1 ist falsch, weil der Key nicht 'greeting'
, sondern () => 'greeting'
ist.
3 ist falsch, weil wir eine neue Funktion erstellen, indem wir sie als Argument übergeben. Objekte interagieren anhand von Referenzen. Funktionen sind Objekte, weshalb zwei Funktionen streng gesehen nie gleich sind, selbst wenn sie sich nicht unterscheiden.
const person = {
name: "Lydia",
age: 21
}
const changeAge = (x = { ...person }) => x.age += 1
const changeAgeAndName = (x = { ...person }) => {
x.age += 1
x.name = "Sarah"
}
changeAge(person)
changeAgeAndName()
console.log(person)
- A:
{name: "Sarah", age: 22}
- B:
{name: "Sarah", age: 23}
- C:
{name: "Lydia", age: 22}
- D:
{name: "Lydia", age: 23}
Antwort
Beide Funktionen, changeAge
und changeAgeAndName
, haben Standard Parameter, nämlich ein neu erstelltes Objekt { ...person }
. Dieses Objekt hat Kopien aller Key/Werte Paare im person
Objekt.
Zuerst führen wir die changeAge
Funktion aus und übergeben ihr das person
Objekt als Argument. Daher wird age
um 1 erhöht. person
ist jetzt { name: "Lydia", age: 22 }
.
Dann führen wir changeAgeAndName
aus, allerdings ohne Parameter. Stattdessen ist der Wert von x
gleich dem neuen Objekt { ...person }
. Da dies ein neues Objekt ist hat es keinen Einfluss auf die Werte des person
Objekts. person
ist immernoch gleich { name: "Lydia", age: 22 }
.
function sumValues(x, y, z) {
return x + y + z;
}
- A:
sumValues([...1, 2, 3])
- B:
sumValues([...[1, 2, 3]])
- C:
sumValues(...[1, 2, 3])
- D:
sumValues([1, 2, 3])
Antwort
Mit dem Spread-Operator ...
können wir Werte spreaden ("verstreichen"). Die sumValues
Funktion erhält drei Argumente: x
, y
und z
. ...[1, 2, 3]
ergibt 1, 2, 3
, was wir an sumValues
übergeben.
let num = 1;
const list = ["🥳", "🤠", "🥰", "🤪"];
console.log(list[(num += 1)]);
- A:
🤠
- B:
🥰
- C:
SyntaxError
- D:
ReferenceError
Antwort
Mit dem+=
Operanden erhöhen wir den Wert von num
um 1
. num
hatte den ursprünglichen Wert 1
und 1 + 1
ergibt 2
. Der Wert an zweiter Stelle im list
Array ist 🥰. console.log(list[2])
gibt 🥰 aus.
const person = {
firstName: "Lydia",
lastName: "Hallie",
pet: {
name: "Mara",
breed: "Dutch Tulip Hound"
},
getFullName() {
return `${this.firstName} ${this.lastName}`;
}
};
console.log(person.pet?.name);
console.log(person.pet?.family?.name);
console.log(person.getFullName?.());
console.log(member.getLastName?.());
- A:
undefined
undefined
undefined
undefined
- B:
Mara
undefined
Lydia Hallie
undefined
- C:
Mara
null
Lydia Hallie
null
- D:
null
ReferenceError
null
ReferenceError
Antwort
Mit den optionalen Kettenoperator ?.
müssen wir nicht mehr prüfen, ob die tiefer genesteten Werte gültig sind oder nicht. Wenn wir die Property von undefined
oder null
aufrufen (nullish) gibt die Expression direkt undefined
aus.
person.pet?.name
: person
hat eine Property pet
: person.pet
ist nicht nullish. Diese hat eine Property name
und gibt Mara
aus.
person.pet?.family?.name
: person
hat eine Property pet
: person.pet
ist nicht nullish. pet
hat keine Property family
, person.pet.family
ist nullish. Die Expression gibt undefined
aus.
person.getFullName?.()
: person
hat eine Property getFullName
: person.getFullName()
ist nicht nullish und wird ausgeführt: Lydia Hallie
wird ausgegeben.
member.getLastName?.()
: member
ist undefined: member.getLastName()
ist nullish. Die Expression gibt undefined
aus.
const groceries = ["banana", "apple", "peanuts"];
if (groceries.indexOf("banana")) {
console.log("We have to buy bananas!");
} else {
console.log(`We don't have to buy bananas!`);
}
- A: We have to buy bananas!
- B: We don't have to buy bananas
- C:
undefined
- D:
1
Antwort
Wir haben die Kondition groceries.indexOf("banana")
an das if-Statement übergeben. groceries.indexOf("banana")
gibt 0
aus, was ein falsy Wert ist. Da die Kondition nicht erfüllt ist wird der else
Block ausgeführt und We don't have to buy bananas!
wird geloggt.
const config = {
languages: [],
set language(lang) {
return this.languages.push(lang);
}
};
console.log(config.language);
- A:
function language(lang) { this.languages.push(lang) }
- B:
0
- C:
[]
- D:
undefined
Antwort
Die Methode language
ist ein setter
. Setter halten keinen Wert, sondern ändern Properties. Wenn eine setter
Methode aufgerufen wird, wird undefined
zurückgegeben.
const name = "Lydia Hallie";
console.log(!typeof name === "object");
console.log(!typeof name === "string");
- A:
false
true
- B:
true
false
- C:
false
false
- D:
true
true
Antwort
typeof name
gibt "string"
aus. Der String "string"
ist truthy, sodass !typeof name
den Boolean-Wert false
ergibt. false === "object"
und false === "string"
geben beide false
aus.
(Würden wir prüfen wollen, oob der Typ (un)gleich zu einem bestimmten anderen Typen ist hätten wir !==
anstelle von !typeof
schreiben müssen)
const add = x => y => z => {
console.log(x, y, z);
return x + y + z;
};
add(4)(5)(6);
- A:
4
5
6
- B:
6
5
4
- C:
4
function
function
- D:
undefined
undefined
6
Antwort
Die add
Funktion gibt eine Arrow Funktion zurück, welche eine Arrow Funktion zurückgibt, welche eine Arrow Funktion zurückgibt. Die erste Funktion erhält ein Argument x
mit dem Wert 4
. Wir führen die zweite Funktion aus, welche ein Argument y
mit dem Wert 5
erhält. Dann führen wir die dritte Funktion aus, die ein Argument z
mit dem Wert 6
erhält. Wenn wir versuchen die Werte von x
, y
und z
der jeweils letzten Arrow Funktion aufzurufen geht die JavaScript Engine in der Scope-Kette nach oben um die jeweiligen Werte zu finden. Das gibt 4
5
6
aus.
async function* range(start, end) {
for (let i = start; i <= end; i++) {
yield Promise.resolve(i);
}
}
(async () => {
const gen = range(1, 3);
for await (const item of gen) {
console.log(item);
}
})();
- A:
Promise {1}
Promise {2}
Promise {3}
- B:
Promise {<pending>}
Promise {<pending>}
Promise {<pending>}
- C:
1
2
3
- D:
undefined
undefined
undefined
Antwort
Die Generator-Funktion range
gibt ein asynchrones Objekt mit Promisen für jeden Wert zurück: Promise{1}
, Promise{2}
, Promise{3}
. Wir setzen die Variable gen
gleich dem asynchronen Objekt. Danach loopen wir mit einer for await ... of
Schleife darüber. Wir setzen die Variable item
gleich dem ausgegebenen Promise: zuerst Promise{1}
, dann Promise{2}
, und dann Promise{3}
. Da wir das Ergebnis von item
await-en (erwarten), werden die gelösten Ergebnisse der Promises ausgegeben: 1
, 2
und 3
.
const myFunc = ({ x, y, z }) => {
console.log(x, y, z);
};
myFunc(1, 2, 3);
- A:
1
2
3
- B:
{1: 1}
{2: 2}
{3: 3}
- C:
{ 1: undefined }
undefined
undefined
- D:
undefined
undefined
undefined
Antwort
myFunc
erwartet ein Objekt mit den Properties x
, y
und z
als Argumente. Da wir nur drei separate Werte anstelle eines Objektes mit den Properties x
, y
und z
({x: 1, y: 2, z: 3}) eingeben, bekommen x
, y
und z
den Standardwert undefined
zugewiesen.
function getFine(speed, amount) {
const formattedSpeed = new Intl.NumberFormat('en-US', {
style: 'unit',
unit: 'mile-per-hour'
}).format(speed);
const formattedAmount = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(amount);
return `The driver drove ${formattedSpeed} and has to pay ${formattedAmount}`;
}
console.log(getFine(130, 300))
- A: The driver drove 130 and has to pay 300
- B: The driver drove 130 mph and has to pay $300.00
- C: The driver drove undefined and has to pay undefined
- D: The driver drove 130.00 and has to pay 300.00
Antwort
Mit der Methode Intl.NumberFormat
können wir einen numerischen Wert in einen sprachabhängigen Wert formatieren. Wir formatieren den Zahlenwert 130
zu einem Wert der Sprache en-US
mit der Einheit (unit
) in mile-per-hour
, was 130 mph
ergibt. Analog formatieren wir 300
als eine Währung (currency
) der Sprache en-US
in USD
, was $300.00
ergibt.
const spookyItems = ['👻', '🎃', '🕸'];
({ item: spookyItems[3] } = { item: '💀' });
console.log(spookyItems);
- A:
["👻", "🎃", "🕸"]
- B:
["👻", "🎃", "🕸", "💀"]
- C:
["👻", "🎃", "🕸", { item: "💀" }]
- D:
["👻", "🎃", "🕸", "[object Object]"]
Antwort
Durch die destrukturierende Zuweisung können wir Werte des Ojekts von der rechten Seite der Zuweisung extrahieren und diese Werte einem Property mit dem selben Namen dem Objekt auf der linken Seite zuweisen. In diesem Fall wird der Wert "💀" an spookyItems[3]
zugewiesen. Das bedeutet, dass wir das Array spookyItems
modifizieren, in dem wir "💀" hinzufügen. Beim Loggen von spookyItems
wird darum ["👻", "🎃", "🕸", "💀"]
ausgegeben.
const name = 'Lydia Hallie';
const age = 21;
console.log(Number.isNaN(name));
console.log(Number.isNaN(age));
console.log(isNaN(name));
console.log(isNaN(age));
- A:
true
false
true
false
- B:
true
false
false
false
- C:
false
false
true
false
- D:
false
true
false
true
Antwort
Mit der Methode Number.isNaN
kann geprüft werden, ob der übergebene Parameter vom Typ Number mit Wert NaN
ist. name
ist kein numerischer Wert, deswegen ist der Rückgabewert von Number.isNaN(name)
in diesem Fall false
. age
ist zwar ein numerischer Wert, aber nicht gleich NaN
, weswegen Number.isNaN(age)
false
ausgibt.
Die Methode isNaN
prüft, ob der Eingabeparameter nicht vom Typ Number ist. name
ist ein String, darum gibt isNaN(name)
true
zurück. age
ist ein numerischer Wert, weswegen isNaN(age)
false
ausgibt.
const randomValue = 21;
function getInfo() {
console.log(typeof randomValue);
const randomValue = 'Lydia Hallie';
}
getInfo();
- A:
"number"
- B:
"string"
- C:
undefined
- D:
ReferenceError
Antwort
Variablen die mit const
deklariert werden, können nicht vor ihrer Initialisierung referenziert werden, das ist die so genannte "zeitweilige tote Zone" (temporal dead zone). In der Funktion getInfo
befindet sich die Variable randomValue
im Geltungsbereich der Funktion. In der Zeile, in welcher der Wert von typeof randomValue
geloggt werden soll, ist die Variable noch nicht initialisiert. Entsprechend wird ein ReferenceError
geworfen! Die Engine versucht nicht in der Kette der Geltungsbereiche hinab zu steigen, da die Variable randomValue
im Geltungsbereich von getInfo
deklariert und damit gefunden wurde.
const myPromise = Promise.resolve('Woah some cool data');
(async () => {
try {
console.log(await myPromise);
} catch {
throw new Error(`Oops didn't work`);
} finally {
console.log('Oh finally!');
}
})();
- A:
Woah some cool data
- B:
Oh finally!
- C:
Woah some cool data
Oh finally!
- D:
Oops didn't work
Oh finally!
Antwort
Im try
-Block loggen wir den mit dem await
-Operator den Wert der Variable myPromise
: "Woah some cool data"
. Da in diesem Block kein Fehler geworfen wird, wird der Code im catch
-Block nicht ausgeführt. Der Code im finally
-Block wird immer ausgeführt, "Oh finally!"
wird geloggt.
const emojis = ['🥑', ['✨', '✨', ['🍕', '🍕']]];
console.log(emojis.flat(1));
- A:
['🥑', ['✨', '✨', ['🍕', '🍕']]]
- B:
['🥑', '✨', '✨', ['🍕', '🍕']]
- C:
['🥑', ['✨', '✨', '🍕', '🍕']]
- D:
['🥑', '✨', '✨', '🍕', '🍕']
Antwort
Mit der Methode flat
erzeugen wir ein neues, "flacheres" Array. Die Tiefe des neuen Arrays hängt vom Parameter ab, den wir an flat
übergeben. In diesem Fall wird der Wert 1
übergeben (welcher der Standardwert der Funktion ist, wir hätten ihn in diesem Fall also nicht explizit übergeben müssen). Das bedeutet, das alle Arrays bis zur ersten Tiefe zusammengefügt werden: ['🥑']
und ['✨', '✨', ['🍕', '🍕']]
in diesem Fall. Das Zusammenfügen dieser beiden Arrays resultiert in: ['🥑', '✨', '✨', ['🍕', '🍕']]
.
class Counter {
constructor() {
this.count = 0;
}
increment() {
this.count++;
}
}
const counterOne = new Counter();
counterOne.increment();
counterOne.increment();
const counterTwo = counterOne;
counterTwo.increment();
console.log(counterOne.count);
- A:
0
- B:
1
- C:
2
- D:
3
Antwort
counterOne
ist eine Instanz der Klasse Counter
. Diese Klasse enthält ein Property count
in seinem Konstruktor, sowie eine Methode increment
. Zuerst wird die Methode increment
zweimal durch counterOne.increment()
aufgerufen. Der Wert von counterOne.count
ist danach 2
.
Danach erzeugen wir eine neue Variable counterTwo
und setzen sie gleich counterOne
. Da Objekte via Referenz übergeben werden, erzeugen wir somit lediglich eine neue Referenz auf den selben Bereich im Speicher, auf den auch counterOne
zeigt. Da der gleiche Speicherbereich verwendet wird, haben alle Änderungen, die am Objekt vorgenommen werden, auf das counterTwo
zeigt, auch Auswirkungen auf counterOne
. Aktuell ist counterTwo.count
somit 2
.
Wir rufen nun counterTwo.increment()
auf, wodurch der Wert von count
auf 3
gesetzt wird. Danach loggen wir den Zustand von counterOne
, wodurch 3
ausgegeben wird.
const myPromise = Promise.resolve(Promise.resolve('Promise!'));
function funcOne() {
myPromise.then(res => res).then(res => console.log(res));
setTimeout(() => console.log('Timeout!', 0));
console.log('Last line!');
}
async function funcTwo() {
const res = await myPromise;
console.log(await res);
setTimeout(() => console.log('Timeout!', 0));
console.log('Last line!');
}
funcOne();
funcTwo();
- A:
Promise! Last line! Promise! Last line! Last line! Promise!
- B:
Last line! Timeout! Promise! Last line! Timeout! Promise!
- C:
Promise! Last line! Last line! Promise! Timeout! Timeout!
- D:
Last line! Promise! Promise! Last line! Timeout! Timeout!
Antwort
Zuerst rufen wir die Funktion funcOne()
auf. In der ersten Zeile in funcOne
wird das Promise myPromise
aufgerufen, was eine asynchrone Operation ist. Während die Engine damit beschäftigt ist dieses Promise zu erfüllen, wird die Funktion funcOne
weiter ausgeführt. Die nächste Zeile ist die asynchrone Funktion setTimeout
, von welcher der Callback an die Web API geschickt wird (siehe mein Artikel zu Event Loops).
Sowohl Promise als auch Timeout sind asynchrone Operationen. Die Funktion läuft also weiter, während sie parallel damit beschäfigt ist diese beiden Operationen zu bearbeiten. Das bedeutet, dass Last line!
zuerst geloggt wird, da dies keine asynchrone Operation ist. Es ist die letzte Zeile von funcOne
, das Promise wird erfüllt und Promise!
geloggt. Da wir jedoch auch funcTwo()
aufrufen, ist der Call Stack nicht leer und der Callback der Funktion setTimeout
kann noch nicht zum Call Stack hinzugefügt werden.
In funcTwo
warten wir zuerst auf das Promise von myPromise
. Mit dem await
-Operator pausieren wir die Ausführung der Funktion bis das Promise erfüllt (oder zurück gewiesen) wurde. Anschließend loggen wir (wieder mit dem await-Operator
, da das Promise selbst ein Promise zurückgibt) den Wert von res
. Dadurch wird Promise!
geloggt.
Die nächste Zeile ist die asynchrone Funktion setTimeout
, deren Callback an die Web API gesendet wird.
Wir kommen zur letzten Zeile in funcTwo
, die Last line!
in der Console ausgibt. Da funcTwo
abgearbeitet und aus dem Call Stack entfernt wurde, ist der Call Stack leer. Die wartenden Callbacks (() => console.log("Timeout!")
aus funcOne
und () => console.log("Timeout!")
aus funcTwo
) werden dem Call Stack nacheinander hinzugefügt. Der erste Callback loggt Timeout!
und wird aus dem Stack entfernt. Anschließend loggt der zweite Callback Timeout!
und wird aus dem Stack entfernt. Somit ist das Ergebnis Last line! Promise! Promise! Last line! Timeout! Timeout!