私はインスタグラムのストーリーに複数の選択肢のJavaScriptの質問を投稿していますが、これもここに投稿します!最終更新日: 6 月 12 日
基本的なものから高度なものまで:JavaScriptをどれだけよく知っているかをテストしたり、知識を少しリフレッシュしたり、コーディング面接の準備をしたりできます。
プロジェクトで自由に使用してください! |
---|
function sayHi() {
console.log(name);
console.log(age);
var name = 'Lydia';
let age = 21;
}
sayHi();
Lydia
undefined
Lydia
ReferenceError
ReferenceError
21
undefined
ReferenceError
関数内で、最初にキーワードを使用して変数を宣言します。これは、変数を定義する行に実際に到達するまで、変数がデフォルト値の で持ち上げられることを意味します(メモリスペースは作成フェーズ中に設定されます)。変数をログに記録しようとする行で変数をまだ定義していないため、 の値を保持します。
name
var
undefined
name
undefined
キーワード (および) を持つ変数はホイストされますが、とは異なり、初期化されません。宣言(初期化)する行の前にはアクセスできません。これは「時間的デッドゾーン」と呼ばれます。変数が宣言される前に変数にアクセスしようとすると、JavaScript は .
let
const
var
ReferenceError
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1);
}
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1);
}
0 1 2
0 1 2
0 1 2
3 3 3
3 3 3
0 1 2
JavaScript のイベント キューのため、コールバック関数はループの実行後に呼び出されます。最初のループの変数はキーワードを使用して宣言されているため、この値はグローバルでした。ループ中に、単項演算子を使用して、毎回の値をインクリメントしました。コールバック関数が呼び出されるまでに、最初の例と等しくなりました。
setTimeout
i
var
i
1
++
setTimeout
i
3
2 番目のループでは、変数はキーワードを使用して宣言されました: (および ) キーワードで宣言された変数はブロックスコープです (ブロックは の間の任意の値です)。各反復中に、新しい値を持ち、各値はループ内でスコープされます。
i
let
let
const
{ }
i
const shape = {
radius: 10,
diameter() {
return this.radius * 2;
},
perimeter: () => 2 * Math.PI * this.radius,
};
console.log(shape.diameter());
console.log(shape.perimeter());
20
62.83185307179586
20
NaN
20
63
NaN
63
の値は通常の関数ですが、の値は矢印関数であることに注意してください。
diameter
perimeter
矢印関数では、キーワードは通常の関数とは異なり、現在の周囲のスコープを参照します。つまり、 を呼び出すと、シェイプオブジェクトではなく、周囲のスコープ(ウィンドウなど)を参照します。
this
perimeter
そのオブジェクトには値がなく、 を返します。
radius
NaN
+true;
!'Lydia';
1
false
false
NaN
false
false
単項プラスは、オペランドを数値に変換しようとします。 は であり、 は である。
true
1
false
0
文字列は真の値です。私たちが実際に求めているのは、「この真実の価値は偽物ですか?」です。これにより、.
'Lydia'
false
const bird = {
size: 'small',
};
const mouse = {
name: 'Mickey',
small: true,
};
mouse.bird.size
mouse[bird.size]
mouse[bird["size"]]
JavaScript では、すべてのオブジェクトキーは文字列です (シンボルでない限り)。文字列として入力しない場合でも、内部では常に文字列に変換されます。
JavaScript はステートメントを解釈 (またはボックス化解除) します。括弧表記を使用すると、最初の開始括弧が表示され、閉じ括弧が見つかるまで続行されます。そうして初めて、ステートメントを評価します。
[
]
mouse[bird.size]: 最初に評価します 、これは です。 収益
bird.size
"small"
mouse["small"]
true
ただし、ドット表記では、これは起こりません。 というキーはありません。次に、ドット表記を使用します。以来、私たちは実際に尋ねています。これは有効ではなく、次のようなエラーがスローされます。
mouse
bird
mouse.bird
undefined
size
mouse.bird.size
mouse.bird
undefined
undefined.size
Cannot read property "size" of undefined
let c = { greeting: 'Hey!' };
let d;
d = c;
c.greeting = 'Hello';
console.log(d.greeting);
Hello
Hey!
undefined
ReferenceError
TypeError
JavaScript では、すべてのオブジェクトは、互いに等しく設定するときに参照によって相互作用します。
まず、変数はオブジェクトに値を保持します。後で、オブジェクトと同じ参照を割り当てます。
c
d
c
1 つのオブジェクトを変更すると、すべてのオブジェクトが変更されます。
let a = 3;
let b = new Number(3);
let c = 3;
console.log(a == b);
console.log(a === b);
console.log(b === c);
true
false
true
false
false
true
true
false
false
false
true
true
new Number()は組み込み関数コンストラクターです。数字のように見えますが、実際には数字ではありません:それはたくさんの追加機能を持っており、オブジェクトです。
演算子を使用すると、同じ値を持つかどうかのみがチェックされます。どちらも の値を持つので、 を返します。
==
3
true
ただし、演算子を使用する場合は、値と型の両方が同じである必要があります。そうではありません:は数字ではなく、オブジェクトです。両方とも戻ります
===
new Number()
false.
class Chameleon {
static colorChange(newColor) {
this.newColor = newColor;
return this.newColor;
}
constructor({ newColor = 'green' } = {}) {
this.newColor = newColor;
}
}
const freddie = new Chameleon({ newColor: 'purple' });
console.log(freddie.colorChange('orange'));
orange
purple
green
TypeError
関数は静的です。静的メソッドは、作成されたコンストラクターでのみ存続するように設計されており、子に渡したり、クラス インスタンスで呼び出したりすることはできません。はカメレオンクラスのインスタンスであるため、関数を呼び出すことはできません。A がスローされます。
colorChange
freddie
TypeError
let greeting;
greetign = {}; // Typo!
console.log(greetign);
{}
ReferenceError: greetign is not defined
undefined
グローバルオブジェクトに空のオブジェクトを作成したばかりなので、オブジェクトをログに記録します。と入力を間違えたとき、JSインタプリタは実際にこれを(またはブラウザで)見ました。
greeting
greetign
global.greetign = {}
window.greetign = {}
これを回避するために、 を使用できます。これにより、変数を any に設定する前に、変数を宣言したことを確認できます。
"use strict"
function bark() {
console.log('Woof!');
}
bark.animal = 'dog';
SyntaxError
"Woof"
ReferenceError
これはJavaScriptで可能です、なぜなら関数はオブジェクトだからです!(プリミティブ型以外はすべてオブジェクトです)
関数は特殊なタイプのオブジェクトです。自分で記述したコードは実際の関数ではありません。関数はプロパティを持つオブジェクトです。このプロパティは呼び出し可能です。
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());
TypeError
SyntaxError
Lydia Hallie
undefined
undefined
JavaScript では、関数はオブジェクトであるため、メソッドはコンストラクター関数オブジェクト自体に追加されます。そのため、 を呼び出すことはできますが、.
getFullName
Person.getFullName()
member.getFullName
TypeError
メソッドをすべてのオブジェクトインスタンスで使用できるようにするには、それをprototypeプロパティに追加する必要があります。
Person.prototype.getFullName = function() {
return `${this.firstName} ${this.lastName}`;
};
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);
Person {firstName: "Lydia", lastName: "Hallie"}
undefined
Person {firstName: "Lydia", lastName: "Hallie"}
Person {firstName: "Sarah", lastName: "Smith"}
Person {firstName: "Lydia", lastName: "Hallie"}
{}
Person {firstName: "Lydia", lastName: "Hallie"}
ReferenceError
については、キーワードを使用しませんでした。を使用する場合、作成する新しい空のオブジェクトを参照します。ただし、追加しない場合は、グローバルオブジェクトを参照します。
sarah
new
new
this
new
this
私たちはそれが等しいと言いました.私たちが実際に行ったことは、定義と. それ自体は 、関数から値を返さないため、残されています。
this.firstName
"Sarah"
this.lastName
"Smith"
global.firstName = 'Sarah'
global.lastName = 'Smith'
sarah
undefined
Person
基本オブジェクトを除くすべてのオブジェクトにプロトタイプがあります。基本オブジェクトは、ユーザーが作成したオブジェクト、またはキーワードを使用して作成されたオブジェクトです。基本オブジェクトは、次のようないくつかのメソッドとプロパティにアクセスできます。これが、組み込みのJavaScriptメソッドを使用できる理由です。このような方法はすべてプロトタイプで利用できます。JavaScript はオブジェクト上で直接見つけることはできませんが、プロトタイプチェーンをたどってそこで見つけるため、アクセスできるようになります。
new
.toString
function sum(a, b) {
return a + b;
}
sum(1, '2');
NaN
TypeError
"12"
3
JavaScript は動的に型付けされる言語です: 特定の変数の種類は指定しません。値は、知らないうちに自動的に別の型に変換できますが、これは暗黙的な型強制と呼ばれます。強制とは、ある型から別の型に変換することです。
この例では、JavaScript は、関数が意味をなして値を返すように、数値を文字列に変換します。数値型 () と文字列型 () を追加すると、数値は文字列として扱われます。のような文字列を連結できるので、ここで起こっていることは .
1
1
'2'
"Hello" + "World"
"1" + "2"
"12"
let number = 0;
console.log(number++);
console.log(++number);
console.log(number);
1
1
2
1
2
2
0
2
2
0
1
2
接尾辞単項演算子 :
++
0)
1)
接頭辞単項演算子 :
++
2)
2)
これにより、.
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`;
"Lydia"
21
["", " is ", " years old"]
["", " is ", " years old"]
"Lydia"
21
"Lydia"
["", " is ", " years old"]
21
タグ付きテンプレートリテラルを使用する場合、最初の引数の値は常に文字列値の配列です。残りの引数は、渡された式の値を取得します。
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 });
You are an adult!
You are still an adult.
Hmm.. You don't have an age I guess
等価性をテストする場合、プリミティブはその値によって比較され、オブジェクトは参照によって比較されます。JavaScript は、オブジェクトがメモリ内の同じ場所への参照を持っているかどうかを確認します。
比較している2つのオブジェクトにはそれがありません:パラメータとして渡したオブジェクトは、等価性をチェックするために使用したオブジェクトとは異なるメモリ内の場所を参照します。
これが両方と戻る理由です.
{ age: 18 } === { age: 18 }
{ age: 18 } == { age: 18 }
false
function getAge(...args) {
console.log(typeof args);
}
getAge(21);
"number"
"array"
"object"
"NaN"
rest パラメーター () を使用すると、残りのすべての引数を配列に「収集」できます。配列はオブジェクトなので、
...args
typeof args
"object"
function getAge() {
'use strict';
age = 21;
console.log(age);
}
getAge();
21
undefined
ReferenceError
TypeError
を使用すると、誤ってグローバル変数を宣言しないようにすることができます。変数を宣言したことはなく、 を使用するため、参照エラーがスローされます。を使用しなかった場合、プロパティがグローバルオブジェクトに追加されるため、機能しました。
"use strict"
age
"use strict"
"use strict"
age
sum
const sum = eval('10*10+5');
105
"105"
TypeError
"10*10+5"
eval文字列として渡されたコードを評価します。この場合のように式の場合は、式を評価します。式は です。これは番号を返します。
10 * 10 + 5
105
sessionStorage.setItem('cool_secret', 123);
に保存されているデータは、タブを閉じると削除されます。
sessionStorage
を使用した場合、たとえば呼び出されない限り、データは永久に存在します。
localStorage
localStorage.clear()
var num = 8;
var num = 10;
console.log(num);
8
10
SyntaxError
ReferenceError
キーワードを使用すると、同じ名前で複数の変数を宣言できます。変数は最新の値を保持します。
var
ブロックスコープであるため、またはブロックスコープであるため、これを行うことはできません。
let
const
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);
false
true
false
true
false
true
true
true
true
true
false
true
true
true
true
true
すべてのオブジェクトキー(シンボルを除く)は、自分で文字列として入力しなくても、内部では文字列です。これが、trueも返す理由です。
obj.hasOwnProperty('1')
セットではそのようには機能しません。私たちのセットにはありません:戻り値。数値型 は を返します。
'1'
set.has('1')
false
1
set.has(1)
true
const obj = { a: 'one', b: 'two', a: 'three' };
console.log(obj);
{ a: "one", b: "two" }
{ b: "two", a: "three" }
{ a: "three", b: "two" }
SyntaxError
同じ名前のキーが 2 つある場合は、キーが置き換えられます。それはまだ最初の位置にありますが、最後に指定された値になります。
基本実行コンテキストはグローバル実行コンテキストであり、コード内のどこからでもアクセスできるものです。
for (let i = 1; i < 5; i++) {
if (i === 3) continue;
console.log(i);
}
1
2
1
2
3
1
2
4
1
3
4
このステートメントは、特定の条件が を返す場合、反復をスキップします。
continue
true
String.prototype.giveLydiaPizza = () => {
return 'Just give Lydia pizza already!';
};
const name = 'Lydia';
console.log(name.giveLydiaPizza())
"Just give Lydia pizza already!"
TypeError: not a function
SyntaxError
undefined
Stringは組み込みのコンストラクターであり、プロパティを追加できます。プロトタイプにメソッドを追加しました。プリミティブ文字列は、文字列プロトタイプ関数によって生成された文字列オブジェクトに自動的に変換されます。したがって、すべての文字列(文字列オブジェクト)はそのメソッドにアクセスできます。
const a = {};
const b = { key: 'b' };
const c = { key: 'c' };
a[b] = 123;
a[c] = 456;
console.log(a[b]);
123
456
undefined
ReferenceError
オブジェクトキーは自動的に文字列に変換されます。オブジェクトをオブジェクトへのキーとして設定しようとしています 、の値で 。
a
123
ただし、オブジェクトを文字列化すると、 になります。だから私たちがここで言っているのは、それです。その後、同じことを再試行できます。 は、暗黙的に文字列化している別のオブジェクトです。それで、.
"[object Object]"
a["[object Object]"] = 123
c
a["[object Object]"] = 456
次に、ログに記録しますが、これは実際には.これを に設定するだけで、 が返されます。
a[b]
a["[object Object]"]
456
456
const foo = () => console.log('First');
const bar = () => setTimeout(() => console.log('Second'));
const baz = () => console.log('Third');
bar();
foo();
baz();
First
Second
Third
First
Third
Second
Second
First
Third
Second
Third
First
関数があり、最初にそれを呼び出しました。しかし、それは最後にログに記録されました。
setTimeout
これは、ブラウザにはランタイムエンジンだけでなく、と呼ばれるものもあるためです。は、最初に使用する関数、たとえばDOMを提供します。
WebAPI
WebAPI
setTimeout
コールバックが WebAPI にプッシュされた後、関数自体 (コールバックは除く) がスタックからポップされます。
setTimeout
これで、呼び出され、ログに記録されます。
foo
"First"
fooスタックからポップされ、呼び出されます。 ログに記録されます。
baz
"Third"
WebAPIは、準備ができたらいつでもスタックに物を追加することはできません。代わりに、コールバック関数をキューと呼ばれるものにプッシュします。
ここで、イベントループが機能し始めます。イベントループは、スタックとタスクキューを調べます。スタックが空の場合は、キューの最初のものを取得し、スタックにプッシュします。
barが呼び出され、ログに記録され、スタックからポップされます。
"Second"
<div onclick="console.log('first div')">
<div onclick="console.log('second div')">
<button onclick="console.log('button')">
Click!
</button>
</div>
</div>
div
div
button
イベントの原因となった最も深いネストされた要素が、イベントのターゲットです。あなたは泡立ちを止めることができます
event.stopPropagation
<div onclick="console.log('div')">
<p onclick="console.log('p')">
Click here!
</p>
</div>
p
div
div
p
p
div
クリックすると、2つのログが表示されます。イベント伝播には、キャプチャ、ターゲット、バブリングの 3 つのフェーズがあります。デフォルトでは、イベントハンドラはバブリングフェーズで実行されます(に設定しない限り)。最も深いネストされた要素から外側に移動します。
p
p
div
useCapture
true
const person = { name: 'Lydia' };
function sayHi(age) {
return `${this.name} is ${age}`;
}
console.log(sayHi.call(person, 21));
console.log(sayHi.bind(person, 21));
undefined is 21
Lydia is 21
function
function
Lydia is 21
Lydia is 21
Lydia is 21
function
両方を使用して、キーワードを参照するオブジェクトを渡すことができます。しかし、すぐにも実行されます!
this
.call
.bind.関数のコピーを返しますが、バインドされたコンテキストを持ちます。すぐには実行されません。
function sayHi() {
return (() => 0)();
}
console.log(typeof sayHi());
"object"
"number"
"function"
"undefined"
この関数は、すぐに呼び出された関数式 (IIFE) の戻り値を返します。この関数は、 型 を返しました。
sayHi
0
"number"
参考までに: 次の値のリストを返すことができます: , , , , , , , , .は を返すことに注意してください。
typeof
undefined
boolean
number
bigint
string
symbol
function
object
typeof null
"object"
0;
new Number(0);
('');
(' ');
new Boolean(false);
undefined;
0
''
undefined
0
new Number(0)
''
new Boolean(false)
undefined
0
''
new Boolean(false)
undefined
8つの偽の値があります。
undefined
null
NaN
false
''(空の文字列)
0
-0
0n(BigInt(0))
関数コンストラクタは、好きで真実です。
new Number
new Boolean
console.log(typeof typeof 1);
"number"
"string"
"object"
"undefined"
typeof 1収益。 収益
"number"
typeof "number"
"string"
const numbers = [1, 2, 3];
numbers[10] = 11;
console.log(numbers);
[1, 2, 3, null x 7, 11]
[1, 2, 3, 11]
[1, 2, 3, empty x 7, 11]
SyntaxError
配列の長さを超える配列内の要素に値を設定すると、JavaScript は「空のスロット」と呼ばれるものを作成します。これらは実際には の値を持ちますが、次のようなものが表示されます。
undefined
[1, 2, 3, empty x 7, 11]
実行する場所によって異なります(ブラウザ、ノードなどごとに異なります)
(() => {
let x, y;
try {
throw new Error();
} catch (x) {
(x = 1), (y = 2);
console.log(x);
}
console.log(x);
console.log(y);
})();
1
undefined
2
undefined
undefined
undefined
1
1
2
1
undefined
undefined
ブロックは引数 を受け取ります。これは、引数を渡すときの変数と同じではありません。この変数はブロックスコープです。
catch
x
x
x
後で、このブロックスコープの変数を に設定し、変数の値を設定します。ここで、 に等しいブロックスコープの変数 をログに記録します。
1
y
x
1
ブロックの外側、 は 、 であり、 です。ブロックの外に出たいときは、 を返し、 を返します。
catch
x
undefined
y
2
console.log(x)
catch
undefined
y
2
JavaScript にはプリミティブ型とオブジェクトしかありません。
プリミティブ型は、および です。
boolean
null
undefined
bigint
number
string
symbol
プリミティブとオブジェクトを区別するのは、プリミティブにはプロパティやメソッドがないことです。ただし、 は に評価され、結果は .これは、文字列などのプリミティブのプロパティまたはメソッドにアクセスしようとすると、JavaScriptはラッパークラスの1つを使用してプリミティブ型を暗黙的にラップし、式が評価された後すぐにラッパーを破棄するためです。を除くすべてのプリミティブは、この動作を示します。
'foo'.toUpperCase()
'FOO'
TypeError
String
null
undefined
[[0, 1], [2, 3]].reduce(
(acc, cur) => {
return acc.concat(cur);
},
[1, 2],
);
[0, 1, 2, 3, 1, 2]
[6, 1, 2]
[1, 2, 0, 1, 2, 3]
[1, 2, 6]
[1, 2]は初期値です。これは私たちが始める値であり、最初の値です。最初のラウンドでは、 であり、 です。それらを連結すると、.
acc
acc
[1,2]
cur
[0, 1]
[1, 2, 0, 1]
次に、 であり、 です。それらを連結して、
[1, 2, 0, 1]
acc
[2, 3]
cur
[1, 2, 0, 1, 2, 3]
!!null;
!!'';
!!1;
false
true
false
false
false
true
false
true
true
true
true
false
nullファルシーです。 収益。 収益。
!null
true
!true
false
""ファルシーです。 収益。 収益。
!""
true
!true
false
1真実です。 収益。 収益。
!1
false
!false
true
setInterval
setInterval(() => console.log('Hi'), 1000);
undefined
一意の ID を返します。この ID を使用して、関数でその間隔をクリアできます。
clearInterval()
[...'Lydia'];
["L", "y", "d", "i", "a"]
["Lydia"]
[[], "Lydia"]
[["L", "y", "d", "i", "a"]]
文字列は反復可能です。スプレッド演算子は、反復可能なすべての文字を 1 つの要素にマップします。
function* generator(i) {
yield i;
yield i * 2;
}
const gen = generator(10);
console.log(gen.next().value);
console.log(gen.next().value);
[0, 10], [10, 20]
20, 20
10, 20
0, 10 and 10, 20
通常の関数は、呼び出し後に途中で停止することはできません。ただし、ジェネレータ機能は途中で「停止」し、後で停止したところから続行できます。ジェネレータ関数がキーワードを検出するたびに、関数はその後に指定された値を生成します。その場合のジェネレータ関数は値を返さず、値を生成することに注意してください。
yield
まず、ジェネレータ関数を に等しいと初期化します。メソッドを使用してジェネレータ関数を呼び出します。ジェネレータ関数を初めて呼び出すときは、 に等しくなります。それは最初のキーワードに遭遇します:それはの値を生み出します。ジェネレータは「一時停止」され、ログに記録されます。
i
10
next()
i
10
yield
i
10
次に、メソッドを使用して関数を再度呼び出します。以前に停止したところから続行を開始しますが、それでも に等しい です。今、それは次のキーワードに遭遇し、そして . は に等しいので、 を返します。この結果、.
next()
i
10
yield
i * 2
i
10
10 * 2
20
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));
"one"
"two"
"two" "one"
"one" "two"
メソッドに複数のプロミスを渡すと、解決/拒否する最初のプロミスを解決/拒否します。メソッドには、最初のプロミス()に500ms、2番目のプロミス()に100msのタイマーを渡します。これは、 が最初に値で解決されることを意味します。 は の値を保持し、ログに記録されます。
Promise.race
setTimeout
firstPromise
secondPromise
secondPromise
'two'
res
'two'
let person = { name: 'Lydia' };
const members = [person];
person = null;
console.log(members);
null
[null]
[{}]
[{ name: "Lydia" }]
まず、プロパティを持つオブジェクトの値を持つ変数を宣言します。
person
name
次に、 という変数を宣言します。その配列の最初の要素を変数の値と等しく設定します。オブジェクトは、互いに等しく設定するときに参照によって相互作用します。ある変数から別の変数に参照を割り当てると、その参照のコピーが作成されます。(彼らは同じ参照を持っていないことに注意してください!
members
person
次に、変数を に設定します。
person
null
変数の値のみを変更し、配列の最初の要素はオブジェクトへの異なる(コピーされた)参照を持っているため、その要素は変更しません。の最初の要素は、元のオブジェクトへの参照を保持します。配列をログに記録しても、最初の要素はオブジェクトの値を保持し、ログに記録されます。
person
members
members
const person = {
name: 'Lydia',
age: 21,
};
for (const item in person) {
console.log(item);
}
{ name: "Lydia" }, { age: 21 }
"name", "age"
"Lydia", 21
["name", "Lydia"], ["age", 21]
ループを使用すると、オブジェクトキー(この場合は と)を反復処理できます。内部的には、オブジェクトキーは文字列です(Symbolでない場合)。すべてのループで、反復処理している現在のキーに等しい値を設定します。まず、 は と等しく、ログに記録されます。次に、 は と等しく、ログに記録されます。
for-in
name
age
item
item
name
item
age
console.log(3 + 4 + '5');
"345"
"75"
12
"12"
演算子の結合規則は、コンパイラが式を左から右または右から左に評価する順序です。これは、すべての演算子の優先順位が同じ場合にのみ発生します。演算子は 1 種類しかありません。また、アソシエティビティは左から右です。
+
3 + 4最初に評価されます。これにより、番号が .
7
7 + '5'強制の結果。JavaScript は数値を文字列に変換します (質問 15 を参照)。演算子を使用して 2 つの文字列を連結できます。 結果は .
"75"
7
+
"7" + "5"
"75"
num
const num = parseInt('7*6', 10);
42
"42"
7
NaN
文字列の最初の数値のみが返されます。基数(解析する数値のタイプを指定するための2番目の引数:基数10、16進数、8進数、2進数など)に基づいて、文字列内の文字が有効かどうかを確認します。基数で有効な数値ではない文字が検出されると、解析を停止し、次の文字を無視します。
parseInt
*は有効な数値ではありません。それは10進数にのみ解析します。 は の値を保持します。
"7"
7
num
7
[1, 2, 3].map(num => {
if (typeof num === 'number') return;
return num * 2;
});
[]
[null, null, null]
[undefined, undefined, undefined]
[ 3 x empty ]
配列をマッピングする場合、の値は現在ループしている要素と等しくなります。この場合、要素は数値であるため、if ステートメントの条件は を返します。map 関数は、新しい配列を作成し、関数から返された値を挿入します。
num
typeof num === "number"
true
ただし、値は返されません。関数から値を返さない場合、関数は を返します。配列内のすべての要素に対して関数ブロックが呼び出されるため、要素ごとに .
undefined
undefined
function getInfo(member, year) {
member.name = 'Lydia';
year = '1998';
}
const person = { name: 'Sarah' };
const birthYear = '1997';
getInfo(person, birthYear);
console.log(person, birthYear);
{ name: "Lydia" }, "1997"
{ name: "Sarah" }, "1998"
{ name: "Lydia" }, "1998"
{ name: "Sarah" }, "1997"
引数は、値がオブジェクトでない限り、値によって渡され、参照によって渡されます。 これはオブジェクトではなく文字列であるため、値によって渡されます。引数を値で渡すと、その値のコピーが作成されます(質問46を参照)。
birthYear
変数には値への参照があります。引数には値への参照もありますが、参照先と同じ値ではありません。に等しいを設定して値を更新すると、 の値のみが更新されます。 はまだに等しいです。
birthYear
"1997"
year
"1997"
birthYear
year
year
"1998"
year
birthYear
"1997"
の値はオブジェクトです。引数には、同じオブジェクトへの (コピーされた) 参照があります。オブジェクトのプロパティを変更すると、両方が同じオブジェクトへの参照を持っているため、の値も変更されます。のプロパティが値と等しくなりました
person
member
member
person
person
name
"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();
It worked! Hello world!
Oh no an error: undefined
SyntaxError: can only throw Error objects
Oh no an error: Hello world!
ステートメントを使用すると、カスタムエラーを作成できます。このステートメントを使用すると、例外をスローできます。例外には、文字列、数値、ブール値、またはオブジェクトを指定できます。この場合、例外は文字列です。
throw
'Hello world!'
ステートメントを使用すると、ブロックで例外がスローされた場合の処理を指定できます。例外がスローされます: 文字列 . は、ログに記録する文字列と等しくなります。この結果、.
catch
try
'Hello world!'
e
'Oh an error: Hello world!'
function Car() {
this.make = 'Lamborghini';
return { make: 'Maserati' };
}
const myCar = new Car();
console.log(myCar.make);
"Lamborghini"
"Maserati"
ReferenceError
TypeError
プロパティを返す場合、プロパティの値は、コンストラクター関数で設定された値ではなく、戻り値と等しくなります。文字列 を返すので、 は に等しくなります。
"Maserati"
myCar.make
"Maserati"
(() => {
let x = (y = 10);
})();
console.log(typeof x);
console.log(typeof y);
"undefined", "number"
"number", "number"
"object", "number"
"number", "undefined"
let x = (y = 10);は実際には次の省略形です。
y = 10;
let x = y;
に等しいに設定すると、実際にはグローバルオブジェクト(ブラウザ、ノード)にプロパティを追加します。ブラウザでは、 は と等しくなります。
y
10
y
window
global
window.y
10
次に、 の値を持つ変数を宣言します。キーワードで宣言された変数はブロックスコープであり、宣言されているブロック内でのみ定義されます。この場合、すぐに呼び出される関数式 (IIFE)。演算子を使用する場合、オペランドは定義されていません:宣言されているブロックの外部にアクセスしようとしています。これは、が定義されていないことを意味します。値が割り当てられていないか宣言されていない値は、 型です。 収益。
x
y
10
let
typeof
x
x
x
"undefined"
console.log(typeof x)
"undefined"
ただし、 に等しいを設定するときにグローバル変数を作成しました。この値は、コード内のどこからでもアクセスできます。 が定義され、 型の値を保持します。 収益。
y
y
10
y
"number"
console.log(typeof y)
"number"
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();
"Woof I am Mara"
TypeError
"Woof I am Mara"
"Woof I am Mara"
"Woof I am Mara"
undefined
TypeError
TypeError
プロトタイプでも、キーワードを使用してオブジェクトからプロパティを削除できます。プロトタイプのプロパティを削除すると、プロトタイプチェーンで使用できなくなります。この場合、関数は 以降のプロトタイプでは使用できなくなりましたが、それでもアクセスを試みます。
delete
bark
delete Dog.prototype.bark
関数ではないものを呼び出そうとすると、aがスローされます。この場合、 は である。
TypeError
TypeError: pet.bark is not a function
pet.bark
undefined
const set = new Set([1, 1, 2, 3, 4]);
console.log(set);
[1, 1, 2, 3, 4]
[1, 2, 3, 4]
{1, 1, 2, 3, 4}
{1, 2, 3, 4}
オブジェクトは一意の値のコレクションであり、値はセット内で一度だけ出現できます。
Set
重複する値でイテラブルを渡しました。セットに同じ値の2つを含めることはできないため、そのうちの1つは削除されます。この結果、.
[1, 1, 2, 3, 4]
1
{1, 2, 3, 4}
// counter.js
let counter = 10;
export default counter;
// index.js
import myCounter from './counter';
myCounter += 1;
console.log(myCounter);
10
11
Error
NaN
インポートされたモジュールは読み取り専用であり、インポートされたモジュールを変更することはできません。それらをエクスポートするモジュールのみが、その値を変更できます。
の値をインクリメントしようとすると、エラーがスローされます:読み取り専用であり、変更できません。
myCounter
myCounter
const name = 'Lydia';
age = 21;
console.log(delete name);
console.log(delete age);
false
true
"Lydia"
21
true
true
undefined
undefined
演算子はブール値を返します: 削除が成功すると、それ以外の場合は .ただし、, or キーワードで宣言された変数は、演算子を使用して削除することはできません。
delete
true
false
var
const
let
delete
変数がキーワードで宣言されたため、削除は成功しません。 が返されます。に等しいを設定すると、実際にはグローバルオブジェクトと呼ばれるプロパティを追加しました。この方法でオブジェクトからプロパティを正常に削除でき、グローバルオブジェクトも削除できるため、 を返します。
name
const
false
age
21
age
delete age
true
const numbers = [1, 2, 3, 4, 5];
const [y] = numbers;
console.log(y);
[[1, 2, 3, 4, 5]]
[1, 2, 3, 4, 5]
1
[1]
分解を通じて、配列から値をアンパックしたり、オブジェクトからプロパティをアンパックしたりできます。例えば:
[a, b] = [1, 2];
の値は であり、 の値は です。私たちが実際に質問でしたことは次のとおりです。
a
1
b
2
[y] = [1, 2, 3, 4, 5];
これは、 の値が配列の最初の値、つまり数値と等しいことを意味します。ログに記録すると、が返されます。
y
1
y
1
const user = { name: 'Lydia', age: 21 };
const admin = { admin: true, ...user };
console.log(admin);
{ admin: true, user: { name: "Lydia", age: 21 } }
{ admin: true, name: "Lydia", age: 21 }
{ admin: true, user: ["Lydia", 21] }
{ admin: true }
スプレッド演算子を使用してオブジェクトを組み合わせることができます。これにより、あるオブジェクトのキーと値のペアのコピーを作成し、それらを別のオブジェクトに追加できます。この場合、オブジェクトのコピーを作成し、オブジェクトに追加します。オブジェクトには、コピーされたキーと値のペアが含まれ、その結果、.
...
user
admin
admin
{ admin: true, name: "Lydia", age: 21 }
const person = { name: 'Lydia' };
Object.defineProperty(person, 'age', { value: 21 });
console.log(person);
console.log(Object.keys(person));
{ name: "Lydia", age: 21 }
["name", "age"]
{ name: "Lydia", age: 21 }
["name"]
{ name: "Lydia"}
["name", "age"]
{ name: "Lydia"}
["age"]
このメソッドを使用すると、オブジェクトに新しいプロパティを追加したり、既存のプロパティを変更したりできます。メソッドを使用してオブジェクトにプロパティを追加すると、デフォルトでは列挙できません。このメソッドは、オブジェクトからすべての列挙可能なプロパティ名 (この場合は のみ) を返します。
defineProperty
defineProperty
Object.keys
"name"
このメソッドを使用して追加されたプロパティは、既定では不変です。この動作は、、およびプロパティを使用してオーバーライドできます。この方法では、オブジェクトに追加するプロパティをより細かく制御できます。
defineProperty
writable
configurable
enumerable
defineProperty
const settings = {
username: 'lydiahallie',
level: 19,
health: 90,
};
const data = JSON.stringify(settings, ['level', 'health']);
console.log(data);
"{"level":19, "health":90}"
"{"username": "lydiahallie"}"
"["level", "health"]"
"{"username": "lydiahallie", "level":19, "health":90}"
の 2 番目の引数は置換子です。置換は関数または配列のいずれかであり、値を文字列化する内容と方法を制御できます。
JSON.stringify
置換が配列の場合、配列に含まれるプロパティ名のみが JSON 文字列に追加されます。この場合、名前と含まれているプロパティのみが除外されます。 は に等しくなります。
"level"
"health"
"username"
data
"{"level":19, "health":90}"
置換が関数の場合、この関数は文字列化するオブジェクト内のすべてのプロパティで呼び出されます。この関数から返される値は、JSON 文字列に追加されるときのプロパティの値になります。値が の場合、このプロパティは JSON 文字列から除外されます。
undefined
let num = 10;
const increaseNumber = () => num++;
const increasePassedNumber = number => number++;
const num1 = increaseNumber();
const num2 = increasePassedNumber(num1);
console.log(num1);
console.log(num2);
10
10
10
11
11
11
11
12
単項演算子は、最初にオペランドの値を返し、次にオペランドの値をインクリメントします。の値は、関数が最初に の値 を返し、 は であり、その後の値のみをインクリメントするためです。
++
num1
10
increaseNumber
num
10
num
num2に渡されたので、です。 は ( の値 .ここでも、単項演算子は最初にオペランドの値を返し、次にオペランドの値をインクリメントします。の値は なので、 は に等しくなります。
10
num1
increasePassedNumber
number
10
num1
++
number
10
num2
10
const value = { number: 10 };
const multiply = (x = { ...value }) => {
console.log((x.number *= 2));
};
multiply();
multiply();
multiply(value);
multiply(value);
20
40
80
160
20
40
20
40
20
20
20
40
NaN
NaN
20
40
ES6では、デフォルト値でパラメータを初期化できます。パラメーターの値は、関数に他の値が渡されていない場合、またはパラメーターの値が の場合、既定値になります。この場合、オブジェクトのプロパティを新しいオブジェクトに分散させるので、デフォルト値は です。
"undefined"
value
x
{ number: 10 }
デフォルトの引数は呼び出し時に評価されます!関数を呼び出すたびに、新しいオブジェクトが作成されます。値を渡さずに関数を最初の 2 回呼び出します: デフォルト値は です。次に、その数値の乗算値をログに記録します。
multiply
x
{ number: 10 }
20
3 回目に multiply を呼び出すときは、引数 (. というオブジェクト) を渡します。演算子は実際には : の値を変更し、乗算された値をログに記録します。
value
*=
x.number = x.number * 2
x.number
20
4回目は、オブジェクトを再度渡します。 は以前に に変更されていたため、.
value
x.number
20
x.number *= 2
40
[1, 2, 3, 4].reduce((x, y) => console.log(x, y));
1
2
3
3
6
4
1
2
2
3
3
4
1
undefined
2
undefined
3
undefined
4
undefined
1
2
undefined
3
undefined
4
この場合、メソッドが受け取る最初の引数はアキュムレータです。2 番目の引数は現在の値です。reduce メソッドでは、配列内のすべての要素に対してコールバック関数を実行し、最終的には 1 つの値になる可能性があります。
reduce
x
y
この例では、値を返さず、単にアキュムレータの値と現在の値をログに記録しています。
アキュムレータの値は、コールバック関数の以前に返された値と同じです。オプションの引数をメソッドに渡さない場合、アキュムレータは最初の呼び出しの最初の要素と等しくなります。
initialValue
reduce
最初の呼び出しでは、アキュムレータ () は であり、現在の値 () は です。コールバック関数から戻るのではなく、アキュムレータと現在の値:をログに記録し、ログに記録します。
x
1
y
2
1
2
関数から値を返さない場合は、.次の呼び出しでは、アキュムレータは で、現在の値は です。 そしてログに記録されます。
undefined
undefined
3
undefined
3
4 回目の呼び出しでは、コールバック関数から再び戻りません。アキュムレータは再び であり、現在の値は です。 そしてログに記録されます。
undefined
4
undefined
4
Dog
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;
}
};
派生クラスでは、 を呼び出す前にキーワードにアクセスすることはできません。これを行おうとすると、ReferenceErrorがスローされます:1と4は参照エラーをスローします。
this
super
キーワードを使用して、指定された引数を使用してその親クラスのコンストラクターを呼び出します。親のコンストラクターは引数を受け取るので、に渡す必要があります。
super
name
name
super
このクラスは、 を拡張し、クラスの追加プロパティとして 2 つの引数を受け取ります。どちらも のコンストラクタ関数に渡す必要がありますが、これはコンストラクタ 2 を使用して正しく行われます。
Labrador
name
Dog
size
Labrador
Labrador
// 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;
running index.js
running sum.js
3
running sum.js
running index.js
3
running sum.js
3
running index.js
running index.js
undefined
running sum.js
キーワードを使用すると、インポートされたすべてのモジュールが事前に解析されます。これは、インポートされたモジュールが最初に実行され、モジュールをインポートするファイル内のコードが後に実行されることを意味します。
import
これは、CommonJSと!を使用すると、コードの実行中に必要に応じて依存関係を読み込むことができます。の代わりに、を使用した場合、はコンソールに記録されます。
require()
import
require()
require
import
running index.js
running sum.js
3
console.log(Number(2) === Number(2));
console.log(Boolean(false) === Boolean(false));
console.log(Symbol('foo') === Symbol('foo'));
true
true
false
false
true
false
true
false
true
true
true
true
すべてのシンボルは完全にユニークです。シンボルに渡される引数の目的は、シンボルに説明を与えることです。シンボルの値は、渡された引数に依存しません。等価性をテストするとき、2つのまったく新しいシンボルを作成しています:最初の、そして2番目の。これらの2つの値は一意であり、互いに等しくない、を返します。
Symbol('foo')
Symbol('foo')
Symbol('foo') === Symbol('foo')
false
const name = 'Lydia Hallie';
console.log(name.padStart(13));
console.log(name.padStart(2));
"Lydia Hallie"
"Lydia Hallie"
" Lydia Hallie"
" Lydia Hallie"
"[13x whitespace]Lydia Hallie"
"[2x whitespace]Lydia Hallie")
" Lydia Hallie"
"Lydia Hallie"
"[1x whitespace]Lydia Hallie"
"Lydia Hallie")
"Lydia Hallie"
"Lyd"
このメソッドを使用すると、文字列の先頭にパディングを追加できます。このメソッドに渡される値は、文字列とパディングの合計長です。文字列の長さは です。 12 + 1 は 13 であるため、文字列の先頭に 1 つのスペースを挿入します。
padStart
"Lydia Hallie"
12
name.padStart(13)
メソッドに渡される引数が配列の長さより小さい場合、パディングは追加されません。
padStart
console.log('🥑' + '💻');
"🥑💻"
257548
演算子を使用すると、文字列を連結できます。この場合、文字列と文字列を連結し、 になります。
+
"🥑"
"💻"
"🥑💻"
function* startGame() {
const answer = yield 'Do you love JavaScript?';
if (answer !== 'Yes') {
return "Oh wow... Guess we're done here";
}
return 'JavaScript loves you back ❤️';
}
const game = startGame();
console.log(/* 1 */); // Do you love JavaScript?
console.log(/* 2 */); // JavaScript loves you back ❤️
game.next("Yes").value
game.next().value
game.next.value("Yes")
game.next.value()
game.next().value
game.next("Yes").value
game.next.value()
game.next.value("Yes")
ジェネレータ関数は、キーワードを見ると実行を「一時停止」します。まず、関数に「JavaScript が好きですか?」という文字列を生成させる必要があります。
yield
game.next().value
最初のキーワードが見つかるまで、すべての行が実行されます。関数内の最初の行にキーワードがあります:実行は最初のyieldで停止します!これは、変数の答えがまだ定義されていないことを意味します!
yield
yield
を呼び出すと、前のものは、この場合、関数に渡されたパラメーターの値に置き換えられます。変数の値は と等しくなります。if ステートメントの条件は を返し、ログに記録されます。
game.next("Yes").value
yield
next()
"Yes"
answer
"Yes"
false
JavaScript loves you back ❤️
console.log(String.raw`Hello\nworld`);
Hello world!
Hello
world
Hello\nworld
Hello\n
world
String.rawエスケープ(、など)が無視される文字列を返します!バックスラッシュは、次のようなものになる可能性があるため、問題になる可能性があります。
\n
\v
\t
const path = `C:\Documents\Projects\table.html`
その結果、次のようになります。
"C:DocumentsProjects able.html"
を使用すると、単にエスケープを無視して印刷します。
String.raw
C:\Documents\Projects\table.html
この場合、文字列は で、ログに記録されます。
Hello\nworld
async function getData() {
return await Promise.resolve('I made it!');
}
const data = getData();
console.log(data);
"I made it!"
Promise {<resolved>: "I made it!"}
Promise {<pending>}
undefined
非同期関数は常にプロミスを返します。まだ約束が解決するのを待たなければなりません:それに等しい設定するために呼び出すと、保留中の約束が返されます。
await
getData()
data
解決された値にアクセスしたい場合は、次のメソッドを使用できます。
"I made it"
.then()
data
data.then(res => console.log(res))
これはログに記録されたでしょう
"I made it!"
function addToList(item, list) {
return list.push(item);
}
const result = addToList('apple', ['banana']);
console.log(result);
['apple', 'banana']
2
true
undefined
このメソッドは、新しい配列の長さを返します。以前は、配列には 1 つの要素 (文字列) が含まれ、長さは .文字列を配列に追加すると、配列には 2 つの要素が含まれ、長さは .これは関数から返されます。
.push()
"banana"
1
"apple"
2
addToList
このメソッドは、元の配列を変更します。配列の長さではなく関数から配列を返す場合は、関数にプッシュした後に戻る必要があります。
push
list
item
const box = { x: 10, y: 20 };
Object.freeze(box);
const shape = box;
shape.x = 100;
console.log(shape);
{ x: 100, y: 20 }
{ x: 10, y: 20 }
{ x: 100 }
ReferenceError
Object.freezeオブジェクトのプロパティを追加、削除、または変更できないようにします (プロパティの値が別のオブジェクトでない限り)。
変数を作成し、フリーズしたオブジェクトと等しく設定すると、フリーズされたオブジェクトも参照します。オブジェクトがフリーズされているかどうかを確認するには、 を使用します。この場合、変数にはフリーズされたオブジェクトへの参照があるため、trueを返します。
shape
box
shape
Object.isFrozen
Object.isFrozen(shape)
shape
は凍結されており、の値はオブジェクトではないため、プロパティを変更することはできません。 は と等しく、ログに記録されます。
shape
x
x
x
10
{ x: 10, y: 20 }
const { name: myName } = { name: 'Lydia' };
console.log(name);
"Lydia"
"myName"
undefined
ReferenceError
右側のオブジェクトからプロパティを解凍すると、その値を という名前の変数に代入します。
name
"Lydia"
myName
を使用すると、右側のプロパティの値を使用して呼び出される新しい変数を作成することを JavaScript に指示します。
{ name: myName }
myName
name
ログを取ろうとするので、定義されていない変数が左側の代入で返されます。後で、の値は破壊割り当てによって格納されます。
name
undefined
Lydia
function sum(a, b) {
return a + b;
}
純粋関数は、同じ引数が渡された場合に常に同じ結果を返す関数です。
この関数は常に同じ結果を返します。合格すると、副作用なしで常に戻ります。と を渡すと、常に が返されます など。これが純粋関数の定義です。
sum
1
2
3
5
10
15
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));
Calculated! 20
Calculated! 20
Calculated! 20
Calculated! 20
From cache! 20
Calculated! 20
Calculated! 20
From cache! 20
From cache! 20
Calculated! 20
From cache! 20
Error
関数はメモ化された機能です。メモ化を使用すると、関数の実行を高速化するために関数の結果をキャッシュできます。この場合、以前に返された値を格納するオブジェクトを作成します。
add
cache
同じ引数で関数を再度呼び出すと、最初にキャッシュにその値が既に取得されているかどうかがチェックされます。その場合は、caches 値が返され、実行時間が節約されます。それ以外の場合、キャッシュされていない場合は、値を計算し、後で格納します。
addFunction
同じ値で関数を 3 回呼び出します: 最初の呼び出しでは、関数の値 when is equal はまだキャッシュされていません。if ステートメントの条件が を返し、else ブロックが実行され、 がログに記録され、結果値がキャッシュ オブジェクトに追加されます。 今のように見えます.
addFunction
num
10
num in cache
false
Calculated! 20
cache
{ 10: 20 }
2 回目は、オブジェクトに返される値が含まれています。if ステートメントの条件は を返し、ログに記録されます。
cache
10
num in cache
true
'From cache! 20'
3回目は、に評価される関数に渡します。オブジェクトには、に対して返される値が含まれています。if ステートメントの条件は を返し、ログに記録されます。
5 * 2
10
cache
10
num in cache
true
'From cache! 20'
const myLifeSummedUp = ['☕', '💻', '🍷', '🍫'];
for (let item in myLifeSummedUp) {
console.log(item);
}
for (let item of myLifeSummedUp) {
console.log(item);
}
0
1
2
3
"☕"
"💻"
"🍷"
"🍫"
"☕"
"💻"
"🍷"
"🍫"
"☕"
"💻"
"🍷"
"🍫"
"☕"
"💻"
"🍷"
"🍫"
0
1
2
3
0
1
2
3
{0: "☕", 1: "💻", 2: "🍷", 3: "🍫"}
for-in ループを使用すると、列挙可能なプロパティを反復処理できます。配列では、列挙可能なプロパティは配列要素の「キー」であり、実際にはインデックスです。配列は次のように表示されます。
{0: "☕", 1: "💻", 2: "🍷", 3: "🍫"}
ここで、キーは列挙可能なプロパティです。 ログに記録されます。
0
1
2
3
for-of ループを使用すると、反復可能オブジェクトを反復処理できます。配列は反復可能です。配列を反復処理すると、変数 "item"は現在反復処理している要素と等しくなり、ログに記録されます。
"☕"
"💻"
"🍷"
"🍫"
const list = [1 + 2, 1 * 2, 1 / 2];
console.log(list);
["1 + 2", "1 * 2", "1 / 2"]
["12", 2, 0.5]
[3, 2, 0.5]
[1, 1, 1]
配列要素は任意の値を保持できます。数値、文字列、オブジェクト、その他の配列、null、ブール値、未定義、およびその他の式 (日付、関数、計算など)。
要素は戻り値と等しくなります。 を返します。
1 + 2
3
1 * 2
2
1 / 2
0.5
function sayHi(name) {
return `Hi there, ${name}`;
}
console.log(sayHi());
Hi there,
Hi there, undefined
Hi there, null
ReferenceError
デフォルトでは、値が関数に渡されていない限り、引数の値は です。この場合、引数の値を渡しませんでした。 は、ログに記録されるものと等しくなります。
undefined
name
name
undefined
ES6では、このデフォルト値をデフォルトのパラメータで上書きできます。例えば:
undefined
function sayHi(name = "Lydia") { ... }
この場合、値を渡さなかった場合、または渡した場合、は常に文字列と等しくなります
undefined
name
Lydia
var status = '😎';
setTimeout(() => {
const status = '😍';
const data = {
status: '🥑',
getStatus() {
return this.status;
},
};
console.log(data.getStatus());
console.log(data.getStatus.call(this));
}, 0);
"🥑"
"😍"
"🥑"
"😎"
"😍"
"😎"
"😎"
"😎"
キーワードの値は、使用する場所によって異なります。メソッドでは、メソッドと同様に、キーワードはメソッドが属するオブジェクトを参照します。メソッドはオブジェクトに属しているため、オブジェクトを参照します。ログに記録すると、オブジェクトのプロパティがログに記録されます。
this
getStatus
this
data
this
data
this.status
status
data
"🥑"
このメソッドを使用すると、キーワードが参照するオブジェクトを変更できます。関数では、キーワードは関数が属するオブジェクトを参照します。グローバルオブジェクトで関数を宣言したので、関数内でキーワードはグローバルオブジェクトを参照します。グローバルオブジェクトには、 という値を持つ status という変数があります。ロギングすると、 がログに記録されます。
call
this
this
setTimeout
setTimeout
this
"😎"
this.status
"😎"
const person = {
name: 'Lydia',
age: 21,
};
let city = person.city;
city = 'Amsterdam';
console.log(person);
{ name: "Lydia", age: 21 }
{ name: "Lydia", age: 21, city: "Amsterdam" }
{ name: "Lydia", age: 21, city: undefined }
"Amsterdam"
変数をオブジェクトで呼び出されるプロパティの値と等しく設定します。このオブジェクトには というプロパティがないため、変数の値は になります。
city
city
person
city
city
undefined
オブジェクト自体を参照していないことに注意してください。変数をオブジェクトのプロパティの現在の値と等しく設定するだけです。
person
city
city
person
次に、文字列に等しく設定します。これは person オブジェクトを変更しません: そのオブジェクトへの参照はありません。
city
"Amsterdam"
オブジェクトをログに記録すると、変更されていないオブジェクトが返されます。
person
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));
"Sorry, you're too young."
"Yay! You're old enough!"
ReferenceError
undefined
and キーワードを持つ変数はブロックスコープです。ブロックは、中括弧 () の間の任意のものです。この場合は、if/else ステートメントの中括弧。宣言されているブロックの外部で変数を参照することはできず、ReferenceError がスローされます。
const
let
{ }
fetch('https://www.website.com/api/user/1')
.then(res => res.json())
.then(res => console.log(res));
fetch
fetch
.then()
2 番目の値は、前の .このように をチェーンし続けると、値が次のハンドラに渡されます。
res
.then
.then
.then
hasName
true
true
function getName(name) {
const hasName = //
}
!!name
name
new Boolean(name)
name.length
を使用すると、の値が真実かファルシーかを判断します。名前が真実である場合、テストしたい場合は、. (これは実際には何であるかです)を返します。
!!name
name
!name
false
!false
!!name
true
に等しいを設定すると、ブール値ではなく、関数に渡した値に等しく設定されます。
hasName
name
hasName
getName
true
new Boolean(true)ブール値自体ではなく、オブジェクトラッパーを返します。
name.lengthreturns the length of the passed argument, not whether it's .
true
console.log('I want pizza'[0]);
"""
"I"
SyntaxError
undefined
In order to get a character at a specific index of a string, you can use bracket notation. The first character in the string has index 0, and so on. In this case, we want to get the element with index 0, the character , which gets logged.
"I'
Note that this method is not supported in IE7 and below. In that case, use .
.charAt()
function sum(num1, num2 = num1) {
console.log(num1 + num2);
}
sum(10);
NaN
20
ReferenceError
undefined
You can set a default parameter's value equal to another parameter of the function, as long as they've been defined before the default parameter. We pass the value to the function. If the function only receives 1 argument, it means that the value for is not passed, and the value of is equal to the passed value in this case. The default value of is the value of , which is . returns .
10
sum
sum
num2
num1
10
num2
num1
10
num1 + num2
20
If you're trying to set a default parameter's value equal to a parameter which is defined after (to the right), the parameter's value hasn't been initialized yet, which will throw an error.
// module.js
export default () => 'Hello world';
export const name = 'Lydia';
// index.js
import * as data from './module';
console.log(data);
{ default: function default(), name: "Lydia" }
{ default: function default() }
{ default: "Hello world", name: "Lydia" }
module.js
With the syntax, we import all exports from the file into the file as a new object called is created. In the file, there are two exports: the default export, and a named export. The default export is a function which returns the string , and the named export is a variable called which has the value of the string .
import * as name
module.js
index.js
data
module.js
"Hello World"
name
"Lydia"
The object has a property for the default export, other properties have the names of the named exports and their corresponding values.
data
default
class Person {
constructor(name) {
this.name = name;
}
}
const member = new Person('John');
console.log(typeof member);
"class"
"function"
"object"
"string"
Classes are syntactical sugar for function constructors. The equivalent of the class as a function constructor would be:
Person
function Person(name) {
this.name = name;
}
Calling a function constructor with results in the creation of an instance of , keyword returns for an instance. returns .
new
Person
typeof
"object"
typeof member
"object"
let newList = [1, 2, 3].push(4);
console.log(newList.push(5));
[1, 2, 3, 4, 5]
[1, 2, 3, 5]
[1, 2, 3, 4]
Error
The method returns the new length of the array, not the array itself! By setting equal to , we set equal to the new length of the array: .
.push
newList
[1, 2, 3].push(4)
newList
4
Then, we try to use the method on . Since is the numerical value , we cannot use the method: a TypeError is thrown.
.push
newList
newList
4
.push
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);
{ constructor: ...}
{ constructor: ...}
{}
{ constructor: ...}
{ constructor: ...}
{}
{ constructor: ...}
undefined
Regular functions, such as the function, have a property, which is an object (prototype object) with a property. Arrow functions however, such as the function, do not have this property. gets returned when trying to access the property using .
giveLydiaPizza
prototype
constructor
giveLydiaChocolate
prototype
undefined
prototype
giveLydiaChocolate.prototype
const person = {
name: 'Lydia',
age: 21,
};
for (const [x, y] of Object.entries(person)) {
console.log(x, y);
}
name
Lydia
age
21
["name", "Lydia"]
["age", 21]
["name", "age"]
undefined
Error
Object.entries(person)returns an array of nested arrays, containing the keys and objects:
[ [ 'name', 'Lydia' ], [ 'age', 21 ] ]
Using the loop, we can iterate over each element in the array, the subarrays in this case. We can destructure the subarrays instantly in the for-of loop, using . is equal to the first element in the subarray, is equal to the second element in the subarray.
for-of
const [x, y]
x
y
The first subarray is , with equal to , and equal to , which get logged. The second subarray is , with equal to , and equal to , which get logged.
[ "name", "Lydia" ]
x
"name"
y
"Lydia"
[ "age", 21 ]
x
"age"
y
21
function getItems(fruitList, ...args, favoriteFruit) {
return [...fruitList, ...args, favoriteFruit]
}
getItems(["banana", "apple"], "pear", "orange")
["banana", "apple", "pear", "orange"]
[["banana", "apple"], "pear", "orange"]
["banana", "apple", ["pear"], "orange"]
SyntaxError
...argsis a rest parameter. The rest parameter's value is an array containing all remaining arguments, and can only be the last parameter! In this example, the rest parameter was the second parameter. This is not possible, and will throw a syntax error.
function getItems(fruitList, favoriteFruit, ...args) {
return [...fruitList, ...args, favoriteFruit];
}
getItems(['banana', 'apple'], 'pear', 'orange');
The above example works. This returns the array
[ 'banana', 'apple', 'orange', 'pear' ]
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 is bigger
6
b is bigger
3
a is bigger
undefined
b is bigger
undefined
undefined
undefined
SyntaxError
In JavaScript, we don't have to write the semicolon () explicitly, however the JavaScript engine still adds them after statements. This is called Automatic Semicolon Insertion. A statement can for example be variables, or keywords like , , , etc.
;
throw
return
break
Here, we wrote a statement, and another value on a new line. However, since it's a new line, the engine doesn't know that it's actually the value that we wanted to return. Instead, it automatically added a semicolon after . You could see this as:
return
a + b
return
return;
a + b;
This means that is never reached, since a function stops running after the keyword. If no value gets returned, like here, the function returns . Note that there is no automatic insertion after statements!
a + b
return
undefined
if/else
class Person {
constructor() {
this.name = 'Lydia';
}
}
Person = class AnotherPerson {
constructor() {
this.name = 'Sarah';
}
};
const member = new Person();
console.log(member.name);
"Lydia"
"Sarah"
Error: cannot redeclare Person
SyntaxError
We can set classes equal to other classes/function constructors. In this case, we set equal to . The name on this constructor is , so the name property on the new instance is .
Person
AnotherPerson
Sarah
Person
member
"Sarah"
const info = {
[Symbol('a')]: 'b',
};
console.log(info);
console.log(Object.keys(info));
{Symbol('a'): 'b'}
["{Symbol('a')"]
{}
[]
{ a: "b" }
["a"]
{Symbol('a'): 'b'}
[]
A Symbol is not enumerable. The Object.keys method returns all enumerable key properties on an object. The Symbol won't be visible, and an empty array is returned. When logging the entire object, all properties will be visible, even non-enumerable ones.
This is one of the many qualities of a symbol: besides representing an entirely unique value (which prevents accidental name collision on objects, for example when working with 2 libraries that want to add properties to the same object), you can also "hide" properties on objects this way (although not entirely. You can still access symbols using the method).
Object.getOwnPropertySymbols()
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))
[1, [2, 3, 4]]
SyntaxError
[1, [2, 3, 4]]
{ name: "Lydia", age: 21 }
[1, 2, 3, 4]
{ name: "Lydia", age: 21 }
Error
{ name: "Lydia", age: 21 }
The function receives an array as its argument. Between the parentheses of the function, we destructure this array right away. You could see this as:
getList
getList
[x, ...y] = [1, 2, 3, 4]
With the rest parameter , we put all "remaining" arguments in an array. The remaining arguments are , and in this case. The value of is an array, containing all the rest parameters. The value of is equal to in this case, so when we log , gets logged.
...y
2
3
4
y
x
1
[x, y]
[1, [2, 3, 4]]
The function receives an object. With arrow functions, we don't have to write curly brackets if we just return one value. However, if you want to instantly return an object from an arrow function, you have to write it between parentheses, otherwise everything between the two braces will be interpreted as a block statement. In this case the code between the braces is not a valid JavaScript code, so a gets thrown.
getUser
SyntaxError
The following function would have returned an object:
const getUser = user => ({ name: user.name, age: user.age })
const name = 'Lydia';
console.log(name());
SyntaxError
ReferenceError
TypeError
undefined
The variable holds the value of a string, which is not a function, thus cannot invoke.
name
TypeErrors get thrown when a value is not of the expected type. JavaScript expected to be a function since we're trying to invoke it. It was a string however, so a TypeError gets thrown: name is not a function!
name
SyntaxErrors get thrown when you've written something that isn't valid JavaScript, for example when you've written the word as . ReferenceErrors get thrown when JavaScript isn't able to find a reference to a value that you're trying to access.
return
retrun
// 🎉✨ This is my 100th question! ✨🎉
const output = `${[] && 'Im'}possible!
You should${'' && `n't`} see a therapist after so much JavaScript lol`;
possible! You should see a therapist after so much JavaScript lol
Impossible! You should see a therapist after so much JavaScript lol
possible! You shouldn't see a therapist after so much JavaScript lol
Impossible! You shouldn't see a therapist after so much JavaScript lol
[]is a truthy value. With the operator, the right-hand value will be returned if the left-hand value is a truthy value. In this case, the left-hand value is a truthy value, so gets returned.
&&
[]
"Im'
""is a falsy value. If the left-hand value is falsy, nothing gets returned. doesn't get returned.
n't
const one = false || {} || null;
const two = null || false || '';
const three = [] || 0 || true;
console.log(one, two, three);
false
null
[]
null
""
true
{}
""
[]
null
null
true
With the operator, we can return the first truthy operand. If all values are falsy, the last operand gets returned.
||
(false || {} || null): the empty object is a truthy value. This is the first (and only) truthy value, which gets returned. is equal to .
{}
one
{}
(null || false || ""): all operands are falsy values. This means that the last operand, gets returned. is equal to .
""
two
""
([] || 0 || ""): the empty array is a truthy value. This is the first truthy value, which gets returned. is equal to .
[]
three
[]
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');
}
firstFunction();
secondFunction();
I have resolved!
second
I have resolved!
second
second
I have resolved!
second
I have resolved!
I have resolved!
second
second
I have resolved!
second
I have resolved!
I have resolved!
second
With a promise, we basically say I want to execute this function, but I'll put it aside for now while it's running since this might take a while. Only when a certain value is resolved (or rejected), and when the call stack is empty, I want to use this value.
We can get this value with both and the keyword in an function. Although we can get a promise's value with both and , they work a bit differently.
.then
await
async
.then
await
In the , we (sort of) put the myPromise function aside while it was running, but continued running the other code, which is in this case. Then, the function resolved with the string , which then got logged after it saw that the callstack was empty.
firstFunction
console.log('second')
I have resolved
With the await keyword in , we literally pause the execution of an async function until the value has been resolved before moving to the next line.
secondFunction
This means that it waited for the to resolve with the value , and only once that happened, we moved to the next line: got logged.
myPromise
I have resolved
second
const set = new Set();
set.add(1);
set.add('Lydia');
set.add({ name: 'Lydia' });
for (let item of set) {
console.log(item + 2);
}
3
NaN
NaN
3
7
NaN
3
Lydia2
[object Object]2
"12"
Lydia2
[object Object]2
The operator is not only used for adding numerical values, but we can also use it to concatenate strings. Whenever the JavaScript engine sees that one or more values are not a number, it coerces the number into a string.
+
The first one is , which is a numerical value. returns the number 3.
1
1 + 2
However, the second one is a string . is a string and is a number: gets coerced into a string. and get concatenated, which results in the string .
"Lydia"
"Lydia"
2
2
"Lydia"
"2"
"Lydia2"
{ name: "Lydia" }is an object. Neither a number nor an object is a string, so it stringifies both. Whenever we stringify a regular object, it becomes . concatenated with becomes .
"[object Object]"
"[object Object]"
"2"
"[object Object]2"
Promise.resolve(5);
5
Promise {<pending>: 5}
Promise {<fulfilled>: 5}
Error
We can pass any type of value we want to , either a promise or a non-promise. The method itself returns a promise with the resolved value (). If you pass a regular function, it'll be a resolved promise with a regular value. If you pass a promise, it'll be a resolved promise with the resolved value of that passed promise.
Promise.resolve
<fulfilled>
In this case, we just passed the numerical value . It returns a resolved promise with the value .
5
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);
Not the same!
They are the same!
ReferenceError
SyntaxError
Objects are passed by reference. When we check objects for strict equality (), we're comparing their references.
===
We set the default value for equal to the object, and passed the object as the value for .
person2
person
person
person1
This means that both values have a reference to the same spot in memory, thus they are equal.
The code block in the statement gets run, and gets logged.
else
They are the same!
const colorConfig = {
red: true,
blue: false,
green: true,
black: true,
yellow: false,
};
const colors = ['pink', 'red', 'blue'];
console.log(colorConfig.colors[1]);
true
false
undefined
TypeError
In JavaScript, we have two ways to access properties on an object: bracket notation, or dot notation. In this example, we use dot notation () instead of bracket notation ().
colorConfig.colors
colorConfig["colors"]
With dot notation, JavaScript tries to find the property on the object with that exact name. In this example, JavaScript tries to find a property called on the object. There is no property called , so this returns . Then, we try to access the value of the first element by using . We cannot do this on a value that's , so it throws a : .
colors
colorConfig
colors
undefined
[1]
undefined
TypeError
Cannot read property '1' of undefined
JavaScript interprets (or unboxes) statements. When we use bracket notation, it sees the first opening bracket and keeps going until it finds the closing bracket . Only then, it will evaluate the statement. If we would've used , it would have returned the value of the property on the object.
[
]
colorConfig[colors[1]]
red
colorConfig
console.log('❤️' === '❤️');
true
false
Under the hood, emojis are unicodes. The unicodes for the heart emoji is . These are always the same for the same emojis, so we're comparing two equal strings to each other, which returns true.
"U+2764 U+FE0F"
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, '✨');
All of them
map
reduce
slice
splice
map
slice
splice
splice
With method, we modify the original array by deleting, replacing or adding elements. In this case, we removed 2 items from index 1 (we removed and ) and added the
splice
'🥑'
'😍'
map, and return a new array, returns an element, and returns a reduced value.
filter
slice
find
reduce
const food = ['🍕', '🍫', '🥑', '🍔'];
const info = { favoriteFood: food[0] };
info.favoriteFood = '🍝';
console.log(food);
['🍕', '🍫', '🥑', '🍔']
['🍝', '🍫', '🥑', '🍔']
['🍝', '🍕', '🍫', '🥑', '🍔']
ReferenceError
We set the value of the property on the object equal to the string with the pizza emoji, . A string is a primitive data type. In JavaScript, primitive data types don't interact by reference.
favoriteFood
info
'🍕'
In JavaScript, primitive data types (everything that's not an object) interact by value. In this case, we set the value of the property on the object equal to the value of the first element in the array, the string with the pizza emoji in this case (). A string is a primitive data type, and interact by value (see my blogpost if you're interested in learning more)
favoriteFood
info
food
'🍕'
Then, we change the value of the property on the object. The array hasn't changed, since the value of was merely a copy of the value of the first element in the array, and doesn't have a reference to the same spot in memory as the element on . When we log food, it's still the original array, .
favoriteFood
info
food
favoriteFood
food[0]
['🍕', '🍫', '🥑', '🍔']
JSON.parse();
With the method, we can parse JSON string to a JavaScript value.
JSON.parse()
// 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();
undefined
ReferenceError
Each function has its own execution context (or scope). The function first looks within its own context (scope) to see if it contains the variable we're trying to access. In this case, the function contains its own variable: we declare the variable with the keyword, and with the value of .
getName
name
getName
name
name
let
'Sarah'
Variables with the keyword (and ) are hoisted, but unlike , don't get initialized. They are not accessible before the line we declare (initialize) them. This is called the "temporal dead zone". When we try to access the variables before they are declared, JavaScript throws a .
let
const
var
ReferenceError
If we wouldn't have declared the variable within the function, the javascript engine would've looked down the scope chain. The outer scope has a variable called with the value of . In that case, it would've logged .
name
getName
name
Lydia
Lydia
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
a
undefined
['a', 'b', 'c']
a
a
['a', 'b', 'c']
With the keyword, we values in a generator function. With the keyword, we can yield values from another generator function, or iterable object (for example an array).
yield
yield
yield*
In , we yield the entire array using the keyword. The value of property on the object returned by the method on () is equal to the entire array .
generatorOne
['a', 'b', 'c']
yield
value
next
one
one.next().value
['a', 'b', 'c']
console.log(one.next().value); // ['a', 'b', 'c']
console.log(one.next().value); // undefined
In , we use the keyword. This means that the first yielded value of , is equal to the first yielded value in the iterator. The iterator is the array . The first yielded value is , so the first time we call , is returned.
generatorTwo
yield*
two
['a', 'b', 'c']
a
two.next().value
a
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`);
I love to program
undefined to program
${(x => x)('I love') to program
TypeError
Expressions within template literals are evaluated first. This means that the string will contain the returned value of the expression, the immediately invoked function in this case. We pass the value as an argument to the arrow function. is equal to , which gets returned. This results in .
(x => x)('I love')
'I love'
x => x
x
'I love'
I love to program
let config = {
alert: setInterval(() => {
console.log('Alert!');
}, 1000),
};
config = null;
setInterval
setInterval
setInterval
config.alert()
null
Normally when we set objects equal to , those objects get garbage collected as there is no reference anymore to that object. However, since the callback function within is an arrow function (thus bound to the object), the callback function still holds a reference to the object. As long as there is a reference, the object won't get garbage collected. Since this is an interval, setting to or -ing won't garbage-collect the interval, so the interval will still be called. It should be cleared with to remove it from memory. Since it was not cleared, the callback function will still get invoked every 1000ms (1s).
null
setInterval
config
config
config
null
delete
config.alert
clearInterval(config.alert)
setInterval
'Hello world!'
const myMap = new Map();
const myFunc = () => 'greeting';
myMap.set(myFunc, 'Hello world!');
//1
myMap.get('greeting');
//2
myMap.get(myFunc);
//3
myMap.get(() => 'greeting');
When adding a key/value pair using the method, the key will be the value of the first argument passed to the function, and the value will be the second argument passed to the function. The key is the function in this case, and the value . is now .
set
set
set
() => 'greeting'
'Hello world'
myMap
{ () => 'greeting' => 'Hello world!' }
1 is wrong, since the key is not but . 3 is wrong, since we're creating a new function by passing it as a parameter to the method. Object interact by reference. Functions are objects, which is why two functions are never strictly equal, even if they are identical: they have a reference to a different spot in memory.
'greeting'
() => 'greeting'
get
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);
{name: "Sarah", age: 22}
{name: "Sarah", age: 23}
{name: "Lydia", age: 22}
{name: "Lydia", age: 23}
Both the and functions have a default parameter, namely a newly created object . This object has copies of all the key/values in the object.
changeAge
changeAgeAndName
{ ...person }
person
First, we invoke the function and pass the object as its argument. This function increases the value of the property by 1. is now .
changeAge
person
age
person
{ name: "Lydia", age: 22 }
Then, we invoke the function, however we don't pass a parameter. Instead, the value of is equal to a new object: . Since it's a new object, it doesn't affect the values of the properties on the object. is still equal to .
changeAgeAndName
x
{ ...person }
person
person
{ name: "Lydia", age: 22 }
6
function sumValues(x, y, z) {
return x + y + z;
}
sumValues([...1, 2, 3])
sumValues([...[1, 2, 3]])
sumValues(...[1, 2, 3])
sumValues([1, 2, 3])
With the spread operator , we can spread iterables to individual elements. The function receives three arguments: , and . will result in , which we pass to the function.
...
sumValues
x
y
z
...[1, 2, 3]
1, 2, 3
sumValues
let num = 1;
const list = ['🥳', '🤠', '🥰', '🤪'];
console.log(list[(num += 1)]);
🤠
🥰
SyntaxError
ReferenceError
With the operand, we're incrementing the value of by . had the initial value , so is . The item on the second index in the array is
+=
num
1
num
1
1 + 1
2
list
console.log(list[2])
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?.());
undefined
undefined
undefined
undefined
Mara
undefined
Lydia Hallie
ReferenceError
Mara
null
Lydia Hallie
null
null
ReferenceError
null
ReferenceError
With the optional chaining operator , we no longer have to explicitly check whether the deeper nested values are valid or not. If we're trying to access a property on an or value (nullish), the expression short-circuits and returns .
?.
undefined
null
undefined
person.pet?.name: has a property named : is not nullish. It has a property called , and returns . : has a property named : is not nullish. does not have a property called , is nullish. The expression returns . : has a property named : is not nullish and can get invoked, which returns . : variable is non existent therefore a gets thrown!
person
pet
person.pet
name
Mara
person.pet?.family?.name
person
pet
person.pet
pet
family
person.pet.family
undefined
person.getFullName?.()
person
getFullName
person.getFullName()
Lydia Hallie
member.getLastName?.()
member
ReferenceError
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!`);
}
undefined
1
We passed the condition to the if-statement. returns , which is a falsy value. Since the condition in the if-statement is falsy, the code in the block runs, and gets logged.
groceries.indexOf("banana")
groceries.indexOf("banana")
0
else
We don't have to buy bananas!
const config = {
languages: [],
set language(lang) {
return this.languages.push(lang);
},
};
console.log(config.language);
function language(lang) { this.languages.push(lang }
0
[]
undefined
The method is a . Setters don't hold an actual value, their purpose is to modify properties. When calling a method, gets returned.
language
setter
setter
undefined
const name = 'Lydia Hallie';
console.log(!typeof name === 'object');
console.log(!typeof name === 'string');
false
true
true
false
false
false
true
true
typeof namereturns . The string is a truthy value, so returns the boolean value . and both return.
"string"
"string"
!typeof name
false
false === "object"
false === "string"
false
(If we wanted to check whether the type was (un)equal to a certain type, we should've written instead of
!==
!typeof)
const add = x => y => z => {
console.log(x, y, z);
return x + y + z;
};
add(4)(5)(6);
4
5
6
6
5
4
4
function
function
undefined
undefined
6
The function returns an arrow function, which returns an arrow function, which returns an arrow function (still with me?). The first function receives an argument with the value of . We invoke the second function, which receives an argument with the value . Then we invoke the third function, which receives an argument with the value . When we're trying to access the value , and within the last arrow function, the JS engine goes up the scope chain in order to find the values for and accordingly. This returns .
add
x
4
y
5
z
6
x
y
z
x
y
4
5
6
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);
}
})();
Promise {1}
Promise {2}
Promise {3}
Promise {<pending>}
Promise {<pending>}
Promise {<pending>}
1
2
3
undefined
undefined
undefined
The generator function returns an async object with promises for each item in the range we pass: , , . We set the variable equal to the async object, after which we loop over it using a loop. We set the variable equal to the returned Promise values: first , then , then . Since we're awaiting the value of , the resolved promise, the resolved values of the promises get returned: , , then .
range
Promise{1}
Promise{2}
Promise{3}
gen
for await ... of
item
Promise{1}
Promise{2}
Promise{3}
item
1
2
3
const myFunc = ({ x, y, z }) => {
console.log(x, y, z);
};
myFunc(1, 2, 3);
1
2
3
{1: 1}
{2: 2}
{3: 3}
{ 1: undefined }
undefined
undefined
undefined
undefined
undefined
myFuncexpects an object with properties , and as its argument. Since we're only passing three separate numeric values (1, 2, 3) instead of one object with properties , and ({x: 1, y: 2, z: 3}), , and have their default value of .
x
y
z
x
y
z
x
y
z
undefined
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))
With the method, we can format numeric values to any locale. We format the numeric value to the locale as a in , which results in . The numeric value to the locale as a in results in .
Intl.NumberFormat
130
en-US
unit
mile-per-hour
130 mph
300
en-US
currency
USD
$300.00
const spookyItems = ['👻', '🎃', '🕸'];
({ item: spookyItems[3] } = { item: '💀' });
console.log(spookyItems);
["👻", "🎃", "🕸"]
["👻", "🎃", "🕸", "💀"]
["👻", "🎃", "🕸", { item: "💀" }]
["👻", "🎃", "🕸", "[object Object]"]
By destructuring objects, we can unpack values from the right-hand object, and assign the unpacked value to the value of the same property name on the left-hand object. In this case, we're assigning the value "
spookyItems[3]
spookyItems
spookyItems
["👻", "🎃", "🕸", "💀"]
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));
true
false
true
false
true
false
false
false
false
false
true
false
false
true
false
true
With the method, you can check if the value you pass is a numeric value and equal to . is not a numeric value, so returns . is a numeric value, but is not equal to , so returns .
Number.isNaN
NaN
name
Number.isNaN(name)
false
age
NaN
Number.isNaN(age)
false
With the method, you can check if the value you pass is not a number. is not a number, so returns true. is a number, so returns .
isNaN
name
isNaN(name)
age
isNaN(age)
false
const randomValue = 21;
function getInfo() {
console.log(typeof randomValue);
const randomValue = 'Lydia Hallie';
}
getInfo();
"number"
"string"
undefined
ReferenceError
Variables declared with the keyword are not referenceable before their initialization: this is called the temporal dead zone. In the function, the variable is scoped in the functional scope of . On the line where we want to log the value of , the variable isn't initialized yet: a gets thrown! The engine didn't go down the scope chain since we declared the variable in the function.
const
getInfo
randomValue
getInfo
typeof randomValue
randomValue
ReferenceError
randomValue
getInfo
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!');
}
})();
Woah some cool data
Oh finally!
Woah some cool data
Oh finally!
Oops didn't work
Oh finally!
In the block, we're logging the awaited value of the variable: . Since no errors were thrown in the block, the code in the block doesn't run. The code in the block always runs, gets logged.
try
myPromise
"Woah some cool data"
try
catch
finally
"Oh finally!"
const emojis = ['🥑', ['✨', '✨', ['🍕', '🍕']]];
console.log(emojis.flat(1));
['🥑', ['✨', '✨', ['🍕', '🍕']]]
['🥑', '✨', '✨', ['🍕', '🍕']]
['🥑', ['✨', '✨', '🍕', '🍕']]
['🥑', '✨', '✨', '🍕', '🍕']
With the method, we can create a new, flattened array. The depth of the flattened array depends on the value that we pass. In this case, we passed the value (which we didn't have to, that's the default value), meaning that only the arrays on the first depth will be concatenated. and in this case. Concatenating these two arrays results in .
flat
1
['🥑']
['✨', '✨', ['🍕', '🍕']]
['🥑', '✨', '✨', ['🍕', '🍕']]
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);
0
1
2
3
counterOneis an instance of the class. The counter class contains a property on its constructor, and an method. First, we invoked the method twice by calling . Currently, is .
Counter
count
increment
increment
counterOne.increment()
counterOne.count
2
Then, we create a new variable , and set it equal to . Since objects interact by reference, we're just creating a new reference to the same spot in memory that points to. Since it has the same spot in memory, any changes made to the object that has a reference to, also apply to . Currently, is .
counterTwo
counterOne
counterOne
counterTwo
counterOne
counterTwo.count
2
We invoke , which sets to . Then, we log the count on , which logs .
counterTwo.increment()
count
3
counterOne
3
const myPromise = Promise.resolve(Promise.resolve('Promise'));
function funcOne() {
setTimeout(() => console.log('Timeout 1!'), 0);
myPromise.then(res => res).then(res => console.log(`${res} 1!`));
console.log('Last line 1!');
}
async function funcTwo() {
const res = await myPromise;
console.log(`${res} 2!`)
setTimeout(() => console.log('Timeout 2!'), 0);
console.log('Last line 2!');
}
funcOne();
funcTwo();
Promise 1! Last line 1! Promise 2! Last line 2! Timeout 1! Timeout 2!
Last line 1! Timeout 1! Promise 1! Last line 2! Promise2! Timeout 2!
Last line 1! Promise 2! Last line 2! Promise 1! Timeout 1! Timeout 2!
Timeout 1! Promise 1! Last line 1! Promise 2! Timeout 2! Last line 2!
First, we invoke . On the first line of , we call the asynchronous function, from which the callback is sent to the Web API. (see my article on the event loop here.)
funcOne
funcOne
setTimeout
Then we call the promise, which is an asynchronous operation.
myPromise
Both the promise and the timeout are asynchronous operations, the function keeps on running while it's busy completing the promise and handling the callback. This means that gets logged first, since this is not an asynchonous operation.
setTimeout
Last line 1!
Since the callstack is not empty yet, the function and promise in cannot get added to the callstack yet.
setTimeout
funcOne
In , the variable gets because is equivalent to since resolving a promise just resolves it's value. The in this line stops the execution of the function until it receives the resolution of the promise and then keeps on running synchronously until completion, so and then are logged and the is sent to the Web API.
funcTwo
res
Promise
Promise.resolve(Promise.resolve('Promise'))
Promise.resolve('Promise')
await
Promise 2!
Last line 2!
setTimeout
Then the call stack is empty. Promises are microtasks so they are resolved first when the call stack is empty so gets to be logged.
Promise 1!
Now, since popped off the call stack, the call stack is empty. The callbacks waiting in the queue ( from , and from ) get added to the call stack one by one. The first callback logs , and gets popped off the stack. Then, the second callback logs , and gets popped off the stack.
funcTwo
() => console.log("Timeout 1!")
funcOne
() => console.log("Timeout 2!")
funcTwo
Timeout 1!
Timeout 2!
sum
sum.js
index.js?
// sum.js
export default function sum(x) {
return x + x;
}
// index.js
import * as sum from './sum';
sum(4)
sum.sum(4)
sum.default(4)
*
With the asterisk , we import all exported values from that file, both default and named. If we had the following file:
*
// info.js
export const name = 'Lydia';
export const age = 21;
export default 'I love JavaScript';
// index.js
import * as info from './info';
console.log(info);
The following would get logged:
{
default: "I love JavaScript",
name: "Lydia",
age: 21
}
For the example, it means that the imported value looks like this:
sum
sum
{ default: function sum(x) { return x + x } }
We can invoke this function, by calling
sum.default
const handler = {
set: () => console.log('Added a new property!'),
get: () => console.log('Accessed a property!'),
};
const person = new Proxy({}, handler);
person.name = 'Lydia';
person.name;
Added a new property!
Accessed a property!
Added a new property!
Accessed a property!
With a Proxy object, we can add custom behavior to an object that we pass to it as the second argument. In this case, we pass the object which contained two properties: and . gets invoked whenever we set property values, gets invoked whenever we get (access) property values.
handler
set
get
set
get
The first argument is an empty object , which is the value of . To this object, the custom behavior specified in the object gets added. If we add a property to the object, will get invoked. If we access a property on the object, gets invoked.
{}
person
handler
person
set
person
get
First, we added a new property to the proxy object (). gets invoked, and logs .
name
person.name = "Lydia"
set
"Added a new property!"
Then, we access a property value on the proxy object, the property on the handler object got invoked. gets logged.
get
"Accessed a property!"
person
const person = { name: 'Lydia Hallie' };
Object.seal(person);
person.name = "Evan Bacon"
person.age = 21
delete person.name
Object.assign(person, { age: 21 })
With we can prevent new properties from being added, or existing properties to be removed.
Object.seal
However, you can still modify the value of existing properties.
person
const person = {
name: 'Lydia Hallie',
address: {
street: '100 Main St',
},
};
Object.freeze(person);
person.name = "Evan Bacon"
delete person.address
person.address.street = "101 Main St"
person.pet = { name: "Mara" }
The method freezes an object. No properties can be added, modified, or removed.
Object.freeze
However, it only shallowly freezes the object, meaning that only direct properties on the object are frozen. If the property is another object, like in this case, the properties on that object aren't frozen, and can be modified.
address
const add = x => x + x;
function myFunc(num = 2, value = add(num)) {
console.log(num, value);
}
myFunc();
myFunc(3);
2
4
3
6
2
NaN
3
NaN
2
Error
3
6
2
4
3
Error
First, we invoked without passing any arguments. Since we didn't pass arguments, and got their default values: num is , and the returned value of the function . To the function, we pass as an argument, which had the value of . returns , which is the value of .
myFunc()
num
value
2
value
add
add
num
2
add
4
value
Then, we invoked and passed the value as the value for the argument . We didn't pass an argument for . Since we didn't pass a value for the argument, it got the default value: the returned value of the function. To , we pass , which has the value of . returns , which is the value of .
myFunc(3)
3
num
value
value
add
add
num
3
add
6
value
class Counter {
#number = 10
increment() {
this.#number++
}
getNum() {
return this.#number
}
}
const counter = new Counter()
counter.increment()
console.log(counter.#number)
10
11
undefined
SyntaxError
In ES2020, we can add private variables in classes by using the . We cannot access these variables outside of the class. When we try to log , a SyntaxError gets thrown: we cannot acccess it outside the class!
#
counter.#number
Counter
const teams = [
{ name: 'Team 1', members: ['Paul', 'Lisa'] },
{ name: 'Team 2', members: ['Laura', 'Tim'] },
];
function* getMembers(members) {
for (let i = 0; i < members.length; i++) {
yield members[i];
}
}
function* getTeams(teams) {
for (let i = 0; i < teams.length; i++) {
// ✨ SOMETHING IS MISSING HERE ✨
}
}
const obj = getTeams(teams);
obj.next(); // { value: "Paul", done: false }
obj.next(); // { value: "Lisa", done: false }
yield getMembers(teams[i].members)
yield* getMembers(teams[i].members)
return getMembers(teams[i].members)
return yield getMembers(teams[i].members)
In order to iterate over the in each element in the array, we need to pass to the generator function. The generator function returns a generator object. In order to iterate over each element in this generator object, we need to use .
members
teams
teams[i].members
getMembers
yield*
If we would've written , , or , the entire generator function would've gotten returned the first time we called the method.
yield
return yield
return
next
const person = {
name: 'Lydia Hallie',
hobbies: ['coding'],
};
function addHobby(hobby, hobbies = person.hobbies) {
hobbies.push(hobby);
return hobbies;
}
addHobby('running', []);
addHobby('dancing');
addHobby('baking', person.hobbies);
console.log(person.hobbies);
["coding"]
["coding", "dancing"]
["coding", "dancing", "baking"]
["coding", "running", "dancing", "baking"]
The function receives two arguments, and with the default value of the array on the object.
addHobby
hobby
hobbies
hobbies
person
First, we invoke the function, and pass as the value for and an empty array as the value for . Since we pass an empty array as the value for , gets added to this empty array.
addHobby
"running"
hobby
hobbies
hobbies
"running"
Then, we invoke the function, and pass as the value for . We didn't pass a value for , so it gets the default value, the property on the object. We push the hobby to the array.
addHobby
"dancing"
hobby
hobbies
hobbies
person
dancing
person.hobbies
Last, we invoke the function, and pass as the value for , and the array as the value for . We push the hobby to the array.
addHobby
"baking"
hobby
person.hobbies
hobbies
baking
person.hobbies
After pushing and , the value of is
dancing
baking
person.hobbies
["coding", "dancing", "baking"]
class Bird {
constructor() {
console.log("I'm a bird. 🦢");
}
}
class Flamingo extends Bird {
constructor() {
console.log("I'm pink. 🌸");
super();
}
}
const pet = new Flamingo();
I'm pink. 🌸
I'm pink. 🌸
I'm a bird. 🦢
I'm a bird. 🦢
I'm pink. 🌸
We create the variable which is an instance of the class. When we instantiate this instance, the on gets called. First, gets logged, after which we call . calls the constructor of the parent class, . The constructor in gets called, and logs .
pet
Flamingo
constructor
Flamingo
"I'm pink. 🌸"
super()
super()
Bird
Bird
"I'm a bird. 🦢"
const emojis = ['🎄', '🎅🏼', '🎁', '⭐'];
/* 1 */ emojis.push('🦌');
/* 2 */ emojis.splice(0, 2);
/* 3 */ emojis = [...emojis, '🥂'];
/* 4 */ emojis.length = 0;
The keyword simply means we cannot redeclare the value of that variable, it's read-only. However, the value itself isn't immutable. The properties on the array can be modified, for example by pushing new values, splicing them, or setting the length of the array to 0.
const
emojis
person
["Lydia Hallie", 21]
[...person]
const person = {
name: "Lydia Hallie",
age: 21
}
[...person] // ["Lydia Hallie", 21]
*[Symbol.iterator]() { for (let x in this) yield* this[x] }
*[Symbol.iterator]() { yield* Object.values(this) }
*[Symbol.iterator]() { for (let x in this) yield this }
Objects aren't iterable by default. An iterable is an iterable if the iterator protocol is present. We can add this manually by adding the iterator symbol , which has to return a generator object, for example by making it a generator function . This generator function has to yield the of the object if we want it to return the array : .
[Symbol.iterator]
*[Symbol.iterator]() {}
Object.values
person
["Lydia Hallie", 21]
yield* Object.values(this)
let count = 0;
const nums = [0, 1, 2, 3];
nums.forEach(num => {
if (num) count += 1
})
console.log(count)
The condition within the loop checks whether the value of is truthy or falsy. Since the first number in the array is , a falsy value, the statement's code block won't be executed. only gets incremented for the other 3 numbers in the array, , and . Since gets incremented by 3 times, the value of is .
if
forEach
num
nums
0
if
count
nums
1
2
3
count
1
count
3
function getFruit(fruits) {
console.log(fruits?.[1]?.[1])
}
getFruit([['🍊', '🍌'], ['🍍']])
getFruit()
getFruit([['🍍'], ['🍊', '🍌']])
null
undefined
[]
null
[]
[]
undefined
undefined
The allows us to optionally access deeper nested properties within objects. We're trying to log the item on index within the subarray that's on index of the array. If the subarray on index in the array doesn't exist, it'll simply return . If the subarray on index in the array exists, but this subarray doesn't have an item on its index, it'll also return .
?
1
1
fruits
1
fruits
undefined
1
fruits
1
undefined
First, we're trying to log the second item in the subarray of . This subarray only contains one item, which means there is no item on index , and returns .
['🍍']
[['🍊', '🍌'], ['🍍']]
1
undefined
Then, we're invoking the function without passing a value as an argument, which means that has a value of by default. Since we're conditionally chaining the item on index of, it returns since this item on index does not exist.
getFruits
fruits
undefined
1
fruits
undefined
1
Lastly, we're trying to log the second item in the subarray of . The item on index within this subarray is , which gets logged.
['🍊', '🍌']
['🍍'], ['🍊', '🍌']
1
🍌
class Calc {
constructor() {
this.count = 0
}
increase() {
this.count ++
}
}
const calc = new Calc()
new Calc().increase()
console.log(calc.count)
0
1
undefined
ReferenceError
We set the variable equal to a new instance of the class. Then, we instantiate a new instance of , and invoke the method on this instance. Since the count property is within the constructor of the class, the count property is not shared on the prototype of . This means that the value of count has not been updated for the instance calc points to, count is still .
calc
Calc
Calc
increase
Calc
Calc
0
const user = {
email: "e@mail.com",
password: "12345"
}
const updateUser = ({ email, password }) => {
if (email) {
Object.assign(user, { email })
}
if (password) {
user.password = password
}
return user
}
const updatedUser = updateUser({ email: "new@email.com" })
console.log(updatedUser === user)
false
true
TypeError
ReferenceError
The function updates the values of the and properties on user, if their values are passed to the function, after which the function returns the object. The returned value of the function is the object, which means that the value of updatedUser is a reference to the same object that points to. equals .
updateUser
password
user
updateUser
user
user
user
updatedUser === user
true
const fruit = ['🍌', '🍊', '🍎']
fruit.slice(0, 1)
fruit.splice(0, 1)
fruit.unshift('🍇')
console.log(fruit)
['🍌', '🍊', '🍎']
['🍊', '🍎']
['🍇', '🍊', '🍎']
['🍇', '🍌', '🍊', '🍎']
First, we invoke the method on the fruit array. The slice method does not modify the original array, but returns the value that it sliced off the array: the banana emoji.
Then, we invoke the method on the fruit array. The splice method does modify the original array, which means that the fruit array now consists of .
At last, we invoke the method on the array, which modifies the original array by adding the provided value, ‘
slice
splice
['🍊', '🍎']
unshift
fruit
['🍇', '🍊', '🍎']
const animals = {};
let dog = { emoji: '🐶' }
let cat = { emoji: '🐈' }
animals[dog] = { ...dog, name: "Mara" }
animals[cat] = { ...cat, name: "Sara" }
console.log(animals[dog])
{ emoji: "🐶", name: "Mara" }
{ emoji: "🐈", name: "Sara" }
undefined
ReferenceError
Object keys are converted to strings.
Since the value of is an object, actually means that we’re creating a new property called equal to the new object. is now equal to .
dog
animals[dog]
"object Object"
animals["object Object"]
{ emoji: "🐶", name: "Mara"}
catis also an object, which means that actually means that we’re overwriting the value of with the new cat properties.
animals[cat]
animals["object Object"]
Logging , or actually since converting the object to a string results , returns the .
animals[dog]
animals["object Object"]
dog
"object Object"
{ emoji: "🐈", name: "Sara" }
const user = {
email: "my@email.com",
updateEmail: email => {
this.email = email
}
}
user.updateEmail("new@email.com")
console.log(user.email)
my@email.com
new@email.com
undefined
ReferenceError
The function is an arrow function, and is not bound to the object. This means that the keyword is not referring to the object, but refers to the global scope in this case. The value of within the object does not get updated. When logging the value of , the original value of gets returned.
updateEmail
user
this
user
user
user.email
my@email.com
const promise1 = Promise.resolve('First')
const promise2 = Promise.resolve('Second')
const promise3 = Promise.reject('Third')
const promise4 = Promise.resolve('Fourth')
const runPromises = async () => {
const res1 = await Promise.all([promise1, promise2])
const res2 = await Promise.all([promise3, promise4])
return [res1, res2]
}
runPromises()
.then(res => console.log(res))
.catch(err => console.log(err))
[['First', 'Second'], ['Fourth']]
[['First', 'Second'], ['Third', 'Fourth']]
[['First', 'Second']]
'Third'
The method runs the passed promises in parallel. If one promise fails, the method rejects with the value of the rejected promise. In this case, rejected with the value . We’re catching the rejected value in the chained method on the invocation to catch any errors within the function. Only gets logged, since rejected with this value.
Promise.all
Promise.all
promise3
"Third"
catch
runPromises
runPromises
"Third"
promise3
method
{ name: "Lydia", age: 22 }
const keys = ["name", "age"]
const values = ["Lydia", 22]
const method = /* ?? */
Object[method](keys.map((_, i) => {
return [keys[i], values[i]]
})) // { name: "Lydia", age: 22 }
entries
values
fromEntries
forEach
このメソッドは、2D 配列をオブジェクトに変換します。各サブ配列の最初の要素がキーになり、各サブ配列の 2 番目の要素が値になります。この場合、配列をマッピングしており、最初の要素が現在のインデックスのキー配列の項目であり、2番目の要素が現在のインデックスのvalues配列の項目である配列を返します。
fromEntries
keys
これにより、正しいキーと値を含むサブ配列の配列が作成され、次のようになります。
{ name: "Lydia", age: 22 }
const createMember = ({ email, address = {}}) => {
const validEmail = /.+\@.+\..+/.test(email)
if (!validEmail) throw new Error("Valid email pls")
return {
email,
address: address ? address : null
}
}
const member = createMember({ email: "my@email.com" })
console.log(member)
{ email: "my@email.com", address: null }
{ email: "my@email.com" }
{ email: "my@email.com", address: {} }
{ email: "my@email.com", address: undefined }
のデフォルト値は空のオブジェクトです。関数によって返されるオブジェクトと等しい変数を設定すると、address の値を渡さなかったため、address の値はデフォルトの空のオブジェクトです。空のオブジェクトは真の値であり、条件付きの条件が を返すことを意味します。アドレスの値は空のオブジェクトです。
address
{}
member
createMember
{}
address ? address : null
true
{}
let randomValue = { name: "Lydia" }
randomValue = 23
if (!typeof randomValue === "string") {
console.log("It's not a string!")
} else {
console.log("Yay it's a string!")
}
It's not a string!
Yay it's a string!
TypeError
undefined
ステートメント内の条件は、の値が と等しいかどうかをチェックします。演算子は、値をブール値に変換します。値が真実であれば戻り値は となり、値がファルシーであれば戻り値は になります。この場合、の戻り値は true 値 であり、 の値はブール値であることを意味します。
if
!typeof randomValue
"string"
!
false
true
typeof randomValue
"number"
!typeof randomValue
false
!typeof randomValue === "string"実際にチェックしているので、常にfalseを返します。条件が返されたため、ステートメントのコードブロックが実行され、ログに記録されます。
false === "string"
false
else
Yay it's a string!