私は毎日、JavaScriptに関する選択問題を Instagramに投稿していますが、ここにも投稿します。
初級から上級まで: JavaScriptの知識のテストを行ったり、知識を少し深めたり、コーディング面接の準備をしてください。:muscle: :rocket: 私はこのレポを毎週新しい質問で更新します。
答えは質問の下の折りたたまれたセクションにあります、クリックすればそれを広げられます。幸運を祈ります。:heart:
中文版本
Русский
Western Balkan
Deutsch
Tiếng Việt
日本語
function sayHi() {
console.log(name);
console.log(age);
var name = "Lydia";
let age = 21;
}
sayHi();- A:
Lydiaとundefined - B:
LydiaとReferenceError - C:
ReferenceErrorと21 - D:
undefinedとReferenceError
答え
関数内で、まず varキーワードを使って name変数を宣言します。これは、変数が定義されている行に実際に到達するまで、変数がデフォルト値の undefinedで初期化される(作成時にメモリ空間が設定される)ことを意味します。
name変数をログ出力を実行している行では、まだ変数を定義していませんので、undefinedの値を保持しています。
letキーワード(またはconst)を持つ変数は持ち上げられますが、 varとは異なり、初期化されません。それらを宣言(初期化)する行の前にはアクセスできません。これは"temporal dead zone"と呼ばれます。
宣言される前に変数にアクセスしようとすると、JavaScriptは 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);
}- A:
0 1 2と0 1 2 - B:
0 1 2と3 3 3 - C:
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
};
shape.diameter();
shape.perimeter();- A:
20と62.83185307179586 - B:
20とNaN - C:
20と63 - D:
NaNと63
答え
diameterの値は正則関数であり、perimeterの値はアロー関数です。
アロー関数では、thisキーワードは通常の関数とは異なり、現在の周囲の範囲を参照します。これは、perimeter関数を呼ぶと、shapeオブジェクトではなく、その周囲の範囲(例えば window)を参照することを意味します。
そのオブジェクトにはradiusという値はなく、undefinedを返します。
+true;
!"Lydia";- A:
1とfalse - B:
falseとNaN - C:
falseとfalse
答え
単項プラスは、オペランドを数値に変換しようとします。trueは1、falseは0です
文字列「Lydia」は truthy valueです。ここで求めているのは、「このtruthy valueは、falsyなのか」ということです。これは falseを返します。
const bird = {
size: "small"
};
const mouse = {
name: "Mickey",
small: true
};- A:
mouse.bird.sizeis not valid - B:
mouse[bird.size]is not valid - C:
mouse[bird["size"]]is not valid - D: これらすべて有効です
答え
JavaScriptでは、すべてのオブジェクトキーは文字列です(Symbolでない限り)。たとえそれを文字列として入力していなくても、それらは常にフードの下で文字列に変換されます。
JavaScriptは、ステートメントを解釈(または、ボックス解除)します。大括弧表記を使用すると、最初の左大括弧 [を見て、右大括弧 ]が見つかるまで進みます。その時だけ、そのステートメントを評価します。
mouse [bird.size]: まず最初に、bird.sizeが評価されます。これは文字列の "small"となります。 mouse["small"]は、trueを返します。
しかし、ドット表記では、これは起こりません。 mouseはbirdと呼ばれるキーを持っていません。 つまりmouse.birdはundefinedとなります。
また、ドット表記を使って sizeを求めます: mouse.bird.size。 mouse.birdは未定義なので、実際にはundefined.sizeを要求しています。これは有効ではないので、Cannot read property "size" of undefinedような、エラーをスローします。
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
答え
JavaScriptでは、すべてのオブジェクトは互いに等しく設定すると参照によって相互作用します。
まず、変数cは、オブジェクトに対する値を保持します。その後、cオブジェクトに対して持っている値と同じ参照でdに代入します。
1つのオブジェクトを変更すると、それらすべてが変更されます。
let a = 3;
let b = new Number(3);
let c = 3;
console.log(a == b);
console.log(a === b);
console.log(b === c);- A:
truefalsetrue - B:
falsefalsetrue - C:
truefalsefalse - D:
falsetruetrue
答え
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" });
freddie.colorChange("orange");- A:
orange - B:
purple - C:
green - D:
TypeError
答え
colorChange関数は静的です。静的メソッドは、それらが作成されたコンストラクタ上でのみ動作するように設計されており、どの子達にも受け継がれません。 freddieは子となりますので、この関数は受け継がれず、freddieインスタンスでは利用できません。
その結果、TypeErrorが投げられます。
let greeting;
greetign = {}; // Typo!
console.log(greetign);- A:
{} - B:
ReferenceError: greetign is not defined - C:
undefined
答え
グローバルオブジェクトに、空のオブジェクトを作成したばかりなので、オブジェクトはログ出力されます。greetingをgreetignと誤って入力した場合、JSインタプリタは実際にこれを global.greetign = {}(またはブラウザの window.greetign = {})と見なします。
これを避けるために、"use strict"を使用する事ができます。これにより、変数を何かに設定する前に、変数宣言したことを確認できます。
function bark() {
console.log("Woof!");
}
bark.animal = "dog";- A: 何も起こらない、これは全く問題ない!
- B:
SyntaxError. この方法で関数にプロパティを追加することはできません。 - C:
undefined - D:
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());- A:
TypeError - B:
SyntaxError - C:
Lydia Hallie - D:
undefinedundefined
答え
通常のオブジェクトのようにコンストラクタにプロパティを追加することはできません。一度にすべてのオブジェクトに機能を追加したい場合は、代わりにプロトタイプを使用する必要があります。だからこの場合は、
Person.prototype.getFullName = function() {
return `${this.firstName} ${this.lastName}`;
};で、member.getFullName()が、機能するはずです。これはなぜ有益なのでしょうか。例えば、このメソッドをコンストラクタ自体に追加したとします。すべてのPersonインスタンスがこのメソッドを必要としなかったのかもしれません。
その場合、多くのメモリスペースを浪費する事でしょう。なぜならそれらはまだその特性を持ち、それは各インスタンスのためにメモリスペースを消費するからです。
その代わりに、プロトタイプに追加するだけであれば、メモリ内の1箇所に配置するだけで、すべてのユーザーがアクセスできます。
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"}とundefined - B:
Person {firstName: "Lydia", lastName: "Hallie"}とPerson {firstName: "Sarah", lastName: "Smith"} - C:
Person {firstName: "Lydia", lastName: "Hallie"}と{} - D:
Person {firstName: "Lydia", lastName: "Hallie"}とReferenceError
答え
sarahでは、newキーワードを使いませんでした。newを使用した場合、作成した新しい空のオブジェクトを参照します。しかし、newを追加しなければ、それはグローバルオブジェクトを参照することとなります。
this.firstNameに"Sarah"を代入、this.lastNameに"Smith"を代入したつもりでしたが、実際に行った事は、global.firstName = 'Sarah' と、global.lastName = 'Smith'を定義したのです。
sarah自体は undefinedのままです。
- A: Target > Capturing > Bubbling
- B: Bubbling > Target > Capturing
- C: Target > Bubbling > Capturing
- D: Capturing > Target > Bubbling
- A: true
- B: false
答え
基本オブジェクトを除き、すべてのオブジェクトにプロトタイプがあります。ベースオブジェクトは.toStringのようないくつかのメソッドとプロパティにアクセスできます。
これが、組み込みのJavaScriptメソッドを使用できる理由です。このような方法はすべてプロトタイプで利用できます。
JavaScriptはそれをあなたのオブジェクト上で直接見つけることはできませんが、プロトタイプチェーンをたどり、見つけます。
function sum(a, b) {
return a + b;
}
sum(1, "2");- A:
NaN - B:
TypeError - C:
"12" - D:
3
答え
JavaScriptは、動的に型付けされた言語です。: 特定の変数がどんな型であるかは指定しません。知らないうちに、値が自動的に別の型に変換されることがあります。この事をimplicit type coercionと呼ばれてます。 Coercionは、ある型から別の型に変換しています。
この例では、関数が意味を成して値を返すために、JavaScriptは数字の1を文字列に変換します。数値型(1)と 文字列型('2')の追加中は、数字は文字列として扱われます。
"Hello"+"World"のように文字列を連結することができるので、ここで起こっているのは"1"+"2"で、これは "12"を返します。
let number = 0;
console.log(number++);
console.log(++number);
console.log(number);- A:
112 - B:
122 - C:
022 - D:
012
答え
接尾辞 単項演算子 ++:
1.値を返す(これは0を返す)
2.値を増やす(numberは現在1です)
接頭辞 単項演算子 ++:
1.値を増やす(数値は2になります)
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`;- A:
"Lydia"21["", " is ", " years old"] - B:
["", " is ", " years old"]"Lydia"21 - C:
"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 });- A:
You are an adult! - B:
You are still an adult. - C:
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);- A:
"number" - B:
"array" - C:
"object" - D:
"NaN"
function getAge() {
"use strict";
age = 21;
console.log(age);
}
getAge();- A:
21 - B:
undefined - C:
ReferenceError - D:
TypeError
答え
"use strict"を使うと、誤ってグローバル変数を宣言しないようにすることができます。変数ageを宣言したことは一度もありませんし、"use strict"を使っているので参照エラーになります。
"use strict"を使用しなかった場合は、プロパティageがグローバルオブジェクトに追加されたことになるので、それは機能します。
const sum = eval("10*10+5");- A:
105 - B:
"105" - C:
TypeError - D:
"10*10+5"
sessionStorage.setItem("cool_secret", 123);- A: 永遠に、データが失われることはありません。
- B: ユーザーがタブを閉じる時
- C: ユーザーがタブだけでなくブラウザ全体を閉じる時。
- D: ユーザーが自分のコンピュータをシャットダウンした時。
答え
sessionStorageに格納されたデータは、タブを閉じた後に削除されます。
localStorageを使用した場合は、localStorage.clear()などが呼び出されない限り、データは永久に存在しているでしょう。
var num = 8;
var num = 10;
console.log(num);- A:
8 - B:
10 - C:
SyntaxError - D:
ReferenceError
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:
falsetruefalsetrue - B:
falsetruetruetrue - C:
truetruefalsetrue - D:
truetruetruetrue
答え
すべてのオブジェクトキー(Symbolsを除く)は、文字列として自分で入力しなくても、内部では文字列です。これが、obj.hasOwnProperty('1')もtrueを返す理由です。
setではそうはいきません。上記のsetには'1' はありません: set.has('1')は、falseを返します。数値型1のset.has(1)は、trueを返します。
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
- A: true
- B: false
- C: 場合によりけり
for (let i = 1; i < 5; i++) {
if (i === 3) continue;
console.log(i);
}- A:
12 - B:
123 - C:
124 - D:
134
String.prototype.giveLydiaPizza = () => {
return "Just give Lydia pizza already!";
};
const name = "Lydia";
name.giveLydiaPizza();- A:
"Just give Lydia pizza already!" - B:
TypeError: not a function - C:
SyntaxError - D:
undefined
答え
Stringはプロパティを追加することができる組み込みコンストラクタです。プロトタイプにメソッドを追加しました。
プリミティブ文字列は、文字列プロトタイプ関数によって生成された文字列オブジェクトに自動的に変換されます。
つまり、すべての文字列(文字列オブジェクト)がそのメソッドにアクセスできます。
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
答え
オブジェクトキーは自動的に文字列に変換されます。オブジェクト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();- A:
FirstSecondThird - B:
FirstThirdSecond - C:
SecondFirstThird - D:
SecondThirdFirst
答え
setTimeout関数があり、それを最初に呼び出したのですが、それは最後にログ出力されました。
これは、ブラウザにはランタイムエンジンがあるだけでなく、WebAPIと呼ばれるものもあるからです。WebAPIは最初にsetTimeout関数を与えてくれます。例えばDOMです。
callbackがWebAPIにプッシュされた後、setTimeout関数自体(コールバックではありません!)がスタックからポップされます。
今、fooが呼び出され、"First"が、ログ出力されています。
fooがスタックからポップされ、bazが呼び出されます。"Third"が、ログ出力されます。
WebAPIは、準備が整ったときにスタックに、なにかを追加することはできません。代わりに、コールバック関数をqueueと呼ばれるものにプッシュします。
event loopが機能し始めるところです。 event loopはスタックとタスクキューを調べます。スタックが空の場合は、キューの最初のものを取り出し、それをスタックにプッシュします。
barが呼び出され、"Second"がログ出力され、スタックからポップされます。
<div onclick="console.log('first div')">
<div onclick="console.log('second div')">
<button onclick="console.log('button')">
Click!
</button>
</div>
</div>- A: 外側
div - B: 内側
div - C:
button - D: ネストしたすべての要素の配列
<div onclick="console.log('div')">
<p onclick="console.log('p')">
Click here!
</p>
</div>- A:
pdiv - B:
divp - C:
p - D:
div
答え
pをクリックすると、pとdivの2つのログが表示されます。イベント伝播中は、キャプチャ、ターゲット、バブリングの3つのフェーズがあります。
デフォルトでは、イベントハンドラはバブリング段階で実行されます(useCaptureをtrueに設定しない限り)。最も深くネストした要素から外側に向かって進みます。
const person = { name: "Lydia" };
function sayHi(age) {
console.log(`${this.name} is ${age}`);
}
sayHi.call(person, 21);
sayHi.bind(person, 21);- A:
undefined is 21Lydia is 21 - B:
functionfunction - C:
Lydia is 21Lydia is 21 - D:
Lydia is 21function
答え
両方とも、thisキーワードが参照したいオブジェクトを渡すことができます。しかし、.callもすぐに実行されます。
.bind.は関数のコピーを返しますが、コンテキストは束縛されています。すぐには実行されません。
function sayHi() {
return (() => 0)();
}
typeof sayHi();- A:
"object" - B:
"number" - C:
"function" - D:
"undefined"
答え
sayHi関数は、即時呼び出し関数式(IIFE)の戻り値を返します。この関数は0を返しました。それは"number"型です。
参考:7つの組み込み型しかありません: null, undefined, boolean, number, string, object, そしてsymbol。関数はオブジェクトなので、"function"型ではなく"object"型です。
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: これらすべてfalsy
答え
falsyの値は6つだけです。
undefinednullNaN0''(empty string)false
new Numberや、new Booleanのような関数コンストラクタは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
答え
配列の長さを超える値を配列内の要素に設定すると、JavaScriptでは、"empty slots"と呼ばれるものを作成します。これらは実際には、undefinedの値を持ちますが、あなたは以下のようなものを見るでしょう
[1, 2, 3, 7 x empty, 11]
実行場所によって異なります(browser、nodeなどによって異なります)。
(() => {
let x, y;
try {
throw new Error();
} catch (x) {
(x = 1), (y = 2);
console.log(x);
}
console.log(x);
console.log(y);
})();- A:
1undefined2 - B:
undefinedundefinedundefined - C:
112 - D:
1undefinedundefined
答え
catchブロックは引数xを受け取ります。これは引数を渡すときの変数と同じxではありません。この変数xはブロックスコープです。
後に、このブロックスコープ変数を1に設定し、変数yの値を設定します。ここで、ブロックスコープ変数xをログ出力します。これは1となります。
catchブロック以外では、xは未定義、yは2です。 catchブロックの外側でconsole.log(x)した場合は、undefinedを返し、yは2を返します。
- A: primitive か object
- B: function か object
- C: ひっかけ問題! objectsのみ
- D: number か object
答え
JavaScriptにはプリミティブ型とオブジェクトしかありません。
プリミティブ型は、boolean, null, undefined, bigint, number, string, そしてsymbolです。
プリミティブとオブジェクトを区別するのは、プリミティブにはプロパティもメソッドもないということです。
ただし、'foo'.toUpperCase()は'FOO'と評価され、TypeErrorにはなりません。これは、文字列のようなプリミティブのプロパティやメソッドにアクセスしようとすると、JavaScriptがラッパークラスの1つ、すなわちStringを使ってオブジェクトを暗黙的にラップし、式が評価された後ラッパーを直ちに破棄するためです。
nullとundefinedを除くすべてのプリミティブはこの振る舞いをします。
[[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]
答え
[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;- A:
falsetruefalse - B:
falsefalsetrue - C:
falsetruetrue - D:
truetruefalse
答え
nullはfalsyです。!nullはtrueを返します。!trueはfalseを返します。
""はfalsyです。!""はtrueを返します。!trueはfalseを返します。
1はtruthyです。!1はfalseを返します。!falseはtrueを返します。
setInterval(() => console.log("Hi"), 1000);- A: ユニークid
- B: 指定されたミリ秒数
- C: 渡された関数
- D:
undefined
[..."Lydia"];- A:
["L", "y", "d", "i", "a"] - B:
["Lydia"] - C:
[[], "Lydia"] - D:
[["L", "y", "d", "i", "a"]]
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 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));- A:
"one" - B:
"two" - C:
"two" "one" - D:
"one" "two"
答え
複数のプロミスをPromise.raceメソッドに渡した時、"resolves/rejects"は、"最初"のプロミスの"resolves/rejects"を行います。
setTimeoutメソッドには、タイマーを渡します: 最初のプロミスには500ms(firstPromise)、2番目のプロミスには100ms(secondPromise)。
これは、secondPromiseが最初に'two'の値で解決されることを意味します。resは'two'の値を保持するようになり、ログ出力されます。
let person = { name: "Lydia" };
const members = [person];
person = null;
console.log(members);- A:
null - B:
[null] - C:
[{}] - D:
[{ name: "Lydia" }]
答え
まず、nameプロパティを持つオブジェクトの値を使って、変数personを宣言します。
それから、membersという変数を宣言します。その配列の最初の要素に、変数personの値を代入します。オブジェクトは、互いをイコールで設定すると、「参照」によって相互作用します。
ある変数から別の変数への"参照"を代入すると、その参照の"コピー"が作成されます。 (それらは、"同じ参照"を持っていないことに注意してください!)
そして、変数personをnullに設定します。
その要素はオブジェクトへの異なる(コピーされた)参照を持っているので、person変数の値を変更するだけで配列の最初の要素は変更されません。 membersの最初の要素はまだ元のオブジェクトへの参照を保持しています。
members配列をログ出力したとき、最初の要素はまだオブジェクトの値を保持しているので、それがログ出力されます。
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]
答え
この場合、for-inループを使うと、オブジェクトキーであるnameとageの繰り返し処理できます。内部的には、オブジェクトキーは文字列です(シンボルではない場合)。
すべてのループで、itemの値は反復している現在のキーに設定されます。まず、itemはnameが代入され、ログに出力されます。その後、itemはageが代入され、ログに出力されます。
console.log(3 + 4 + "5");- A:
"345" - B:
"75" - C:
12 - D:
"12"
答え
演算子結合性は、コンパイラーが式を評価する順序(左から右または右から左)となります。これは、すべての演算子が同じ優先順位を持つ場合にのみ発生します。演算子の種類は1つだけです: +。さらに、結合性は左から右です。
3 + 4が最初に評価されます。これは数字の7になります。
7 + '5'は、強制的に"75"になります。 JavaScriptでは、数字の7を文字列に変換します。質問15を参照してください。2つの文字列を演算子の+を使って連結することができます。よって、"7" + "5"は、"75"になります。
const num = parseInt("7*6", 10);- A:
42 - B:
"42" - C:
7 - D:
NaN
答え
文字列の最初の数字だけが返されます。"基数"(解析する数値の種類を指定するための2番目の引数: 基数10, 16進数, 8進数, 2進数など)に基づいて、parseIntは文字列内の文字が有効かどうかをチェックします。基数の中で有効な数字ではない文字に出会うと、構文解析を停止して次の文字を無視します。
*は、有効な数字ではありません。"7"を、10進数の7に解析するだけです。そのままnumは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 ]
答え
配列をマッピングするとき、numの値に代入されるのは、ループで渡ってくる要素となります。この場合、要素は数値なので、ifステートメント typeof num === "number"の条件はtrueを返します。 map関数は新しい配列を作成して関数から返された値を挿入します。
ただし、値は返されません。関数から値を返さないと、関数は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);- A:
{ name: "Lydia" }, "1997" - B:
{ name: "Sarah" }, "1998" - C:
{ name: "Lydia" }, "1998" - D:
{ name: "Sarah" }, "1997"
答え
値がオブジェクトでない限り、引数は"値"によって渡され、その後、"参照"によって渡されます。 birthYearはオブジェクトではなく文字列なので、値で渡されます。引数を値で渡すと、その値の"コピー"が作成されます(質問46を参照)。
変数birthYearは、値"1997"への参照を持ちます。引数yearは、値"1997"も参照していますが、それはbirthYearが参照しているのと同じ値ではありません。yearに"1998"を代入することによってyearの値を更新したとしても、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();- 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!
答え
throwステートメントを使って、カスタムエラーを作ることができます。このステートメントで、あなたは例外を投げることができます。例外は、string, number, boolean, objectのいずれかとなります。上記の場合だと、例外は文字列'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);- A:
"Lamborghini" - B:
"Maserati" - C:
ReferenceError - D:
TypeError
答え
プロパティを返すと、そのプロパティの値は、コンストラクタ関数で設定された値ではなく、"戻り値"となります。 "Maserati"という文字列を返すので、myCar.makeは "Maserati"となります。
(() => {
let x = (y = 10);
})();
console.log(typeof x);
console.log(typeof y);- A:
"undefined", "number" - B:
"number", "number" - C:
"object", "number" - D:
"number", "undefined"
答え
let x = y = 10; is actually shorthand for:
y = 10;
let x = y;yに10を代入すると、実際にはグローバルオブジェクトにプロパティyが追加されます(ブラウザではwindow、nodeではglobal)。ブラウザでは、window.yは10となりました。
それから、変数xを10である値yで宣言します。letキーワードで宣言された変数は"ブロックスコープ"となり、宣言されたブロック内でのみ定義されます。この場合は即時関数(IIFE)となります。
typeof演算子使用時、オペランドxは定義されていません: 宣言されているブロックの外側でxにアクセスしようとしています。これはxが定義されていないことを意味します。
値が割り当てられていない、または宣言されていない値は"undefined"型となります。なのでconsole.log(typeof x)は"undefined"を返します。
yに関しては、yに10を代入するときにグローバル変数yを作成しました。この値は、コード内のどこからでもアクセスできます。yが定義されていて、"number"型の値を保持します。よってconsole.log(typeof y)は"number"を返します。
