あなたは何問解ける？JavaScript構文クイズ

JavaScriptの基本構文に関するクイズ。全20問です。
あなたは何問正解できるでしょうか？
問題のコードはGoogle Chromeのディベロッパーツールで動作確認しています。

## 問1 以下のコードの実行結果として正しいものを選べ。

```javascript
var str1 = new String("1");
var str2 = "1";
var num1 = new Number(1);
var num2 = 1;

console.log(
    str1 == num1, 
    str1 == num2, 
    str2 == num1, 
    str2 == num2
);
```

1. true true true true
2. false true true true
3. false false true true
4. false false false true

<details>
<summary>答え</summary><div>
2
JavaScriptでは数値も文字列もプリミティブ型として扱われますが、newでインスタンスを作ると参照型になります。
参照型同士を==で比較すると参照を比較しますが、どちらかがプリミティブ型であれば値をプリミティブ型に変換してから比較します。
</div></details>

## 問2 以下のコードの実行結果として正しいものを選べ。

```javascript
var num1 = new Number(1);
var num2 = new Number(1);
var num3 = 1;
var num4 = 1;

console.log(
    num1 == num2, 
    num1 === num2,
    num1 == num3,
    num1 === num3,
    num3 == num4,
    num3 === num4
);
```

1. ture true true true true true
2. true true false false true true 
3. false true false true true true
4. false false true false true true

<details>
<summary>答え</summary><div>
4
==で比較したときの挙動は問1で解説した通りです。
===で参照型を比較するときは==と同じく参照を比較します。
プリミティブ型を比較するときは型まで比較するので==のように参照型をプリミティブ型に変換するような挙動はありません。
</div></details>

## 問3 以下のコードの実行結果として正しいものを選べ。

```javascript

console.log(
    1 / 0,
    0 / 0,
    NaN / NaN,
    Infinity / Infinity
);
```

1. Infinity NaN NaN NaN
2. NaN NaN NaN NaN
3. Infinity NaN 1 1
4. Infinity Infinity Infinity Infinity

<details>
<summary>答え</summary><div>
1
0を0で割るとNaNになります。
正の数を0で割るとInfinityになり、負の数を0で割ると-Infinityになります。
InfinityをInfinityで割ったり、引いたりするとNaNになります。
</div></details>

## 問4 以下のコードの実行結果として正しいものを選べ。

```javascript
var infinity1 = Infinity;
var infinity2 = Infinity;
var nan1 = NaN;
var nan2 = NaN;

console.log(
    infinity1 == infinity2,
    infinity1 - infinity2,
    infinity1 + infinity2,
    infinity1 * -1,
    nan1 == nan2,
    nan1 === nan2
);
```

1. true NaN Infinity -Infinity false false
2. false Infinity Infinity Infinity false false
3. true NaN Infinity -Infinity true true
4. true NaN NaN NaN false false

<details>
<summary>答え</summary><div>
1
NaNを比較するとfalseが返ります。
</div></details>

## 問5 以下のコードの実行結果として正しいものを選べ。

```javascript
var message = "hello";

function hello() {
    var message = "world";
    console.log(message);
}

console.log(hello());
console.log(message);
```

1. world null hello
2. world null world
3. world undefined hello
4. world undefined world

<details>
<summary>答え</summary><div>
3
戻り値がない関数の結果はundefinedになります。
また、関数内でvarを使って変数を定義するとローカル変数となります。
</div></details>

## 問6 以下のコードの実行結果として正しいものを選べ。

```javascript
var str1 = new String("03 ");
var str2 = " 2 ";

console.log(
    str1 + str2,
    str1 - str2,
    str1 * str2,
    str1 / str2
);
```

1. 03  2  1 6 1.5
2. 5 1 6 1.5
3. エラー
4. 03 2  NaN Nan NaN

<details>
<summary>答え</summary><div>
1
文字列で変数を定義して足し算をすると文字列結合になりますが、その他の算術演算子を使うとNaNが返ります。
ただし、数字とスペースなど、数値に変換できる組み合わせであれば足し算以外は数字に変換してから実行されます。
</div></details>

## 問7 以下のコードの実行結果として正しいものを選べ。

```javascript
var people = ["Alice", "Bob", "Chris"];

delete people[1];

people[4] = "Eliza";

for(var i = 0; i < people.length; i++) {
    console.log(people[i]);
}
```
1. Alice Chris Eliza
2. エラー
3. Alice undefined Chris undefined Eliza
4. Alice null Chris null Eliza


<details>
<summary>答え</summary><div>
3
delete演算子を使うとオブジェクトのプロパティや配列の要素を削除できます。
ただし配列の場合は要素自体はundefinedになり、要素数は変わりません。
また、JavaScriptの配列は可変なのでインデックスを指定して要素を追加できます。
指定したインデックスよりも前の要素が存在しない場合はそれらの要素にはundefinedが入ります。
</div></details>

## 問8 以下のコードの実行結果として正しいものを選べ。

```javascript
var name = "John";

function greet() {
    console.log("I'm " + name);
    var name = "Bob";
}
greet();
```

1. I'm Bob
2. I'm John
3. I'm undefined
4. エラー

<details>
<summary>答え</summary><div>
3
関数内で変数を定義した場合、定義した位置に関わらず、最初にundefinedとして定義されます。
これを変数の巻き上げといいます。
</div></details>

## 問9 以下のコードの実行結果として正しいものを選べ。

```javascript

var person = {name: "Alice"};

console.log(person.name);
console.log(person.age);
console.log(age);
```
1. Alice エラー エラー
2. Alice undefined エラー
3. Alice undefined undefined
4. Alice null undefied

<details>
<summary>答え</summary><div>
2
オブジェクトのプロパティを参照したときに、そのプロパティが存在しなければundefinedが返ります。
存在しない変数を参照しようとした場合、ReferenceErrorが発生します。
</div></details>

## 問10 ①〜④の中でのコメントを外して実行したときにエラーが発生しないものの組み合わせとして正しいものを選べ。

```javascript
var num = 100;

function greet() {
    var message1 = "Good morning";
}

if(num > 0) {
    greet();
    var message2 = "Hello";
    let message3 = "Good after noon";
    const message4 = "Good eveining";
}

// ① console.log(message1);
// ② console.log(message2);
// ③ console.log(message3);
// ④ console.log(message4);

```

1. ①、②
2. ②のみ
3. ①のみ
4. ①、②、③、④

<details>
<summary>答え</summary><div>
2
JavaScriptではブロック内であってもvarで変数を定義するとグローバルスコープで定義されます。
ただし、関数内で定義した場合はローカルスコープになります。
関数以外でスコープを制限したい場合はletを使うと良いです。
</div></details>

# 問11 ①〜④の中でのコメントを外して実行したときにエラーが発生しないものの組み合わせとして正しいものを選べ。

```javascript
var num = 0;

function greet() {
    var message1 = "Good morning";
}

if(num > 0) {
    greet();
    var message2 = "Hello";
    let message3 = "Good after noon";
    const message4 = "Good eveining";
}

// ① console.log(message1);
// ② console.log(message2);
// ③ console.log(message3);
// ④ console.log(message4);

```

1. ①、②
2. ②のみ
3. ①のみ
4. ①、②、③、④

<details>
<summary>答え</summary><div>
2
問10と同じ。
varで宣言するとその行が実行されるかどうかに関わらず変数が定義されます。
</div></details>


# 問12 以下のコードの実行結果として正しいものを選べ。

```javascript
var global = "Global";

function f1() {
    console.log(global);
}

function f2() {
    var global = "F2";
    f1();
    console.log(global);
}

f2();
```

1. Global F2
2. F2 F2
3. Global Global
4. undefined F2

<details>
<summary>答え</summary><div>
1
こちらもスコープの問題です。
f2関数内でglobalを宣言した後にf1関数を呼んでいますが、f1のglobalはグローバルスコープのglobalを参照します。
</div></details>


# 問13 ①〜③の中からpeople内の要素が出力されるものの組み合わせとして正しいものを選べ。

```javascript
var people = ["Alice", "Bob", "Chris"];

// ①
for(var p in people) {
    console.log(p);
}

// ②
for(var p of people) {
    console.log(p);
}

// ③
for(var i = 0; i < people.length; i++) {
    console.log(people[i]);
}
```

1. ①、②、③
2. ①、③
3. ②、③
4. ③のみ

<details>
<summary>答え</summary><div>
3
inを使ってループすると配列のインデックスを取得できます。
ofを使ってループすると配列の要素を取得できます。
</div></details>


# 問14 以下のコードの実行結果として正しいものを選べ。

```javascript
function Person(name) {
    this.name = name;
}
Person.age = 10;

var person1 = new Person("John");
console.log(person1.name, person1.age);

person1.age = 11;
console.log(person1.age);
```

1. エラー
2. John 10 11
3. John undefined 11
4. John undefined undefined

<details>
<summary>答え</summary><div>
3
「インスタンス.プロパティ名 = 値」とすることで新しくプロパティを追加できます。
また、「オブジェクト名.prototype.プロパティ名 = 値」とすることでもプロパティを追加できます。
上記のコードであれば4行目を「Person.prototype.age = 10」に修正すれば追加でき、選択肢2の結果になります。
</div></details>

# 問15 以下のコードの実行結果として正しいものを選べ。

```javascript
Date.prototype.getFormattedDate = function(formatString) {

    formatString = formatString.replace(/yyyy/g, this.getFullYear());
    formatString = formatString.replace(/MM/g, ("0" + (this.getMonth())).slice(-2));
    formatString = formatString.replace(/dd/g, ("0" + this.getDate()).slice(-2));
    formatString = formatString.replace(/HH/g, ("0" + this.getHours()).slice(-2));
    formatString = formatString.replace(/mm/g, ("0" + this.getMinutes()).slice(-2));
    formatString = formatString.replace(/ss/g, ("0" + this.getSeconds()).slice(-2));

    return formatString;
}
// 2019年5月25日 9時0分0秒に実行
var date = new Date();
console.log(date.getFormattedDate("yyyy-MM-dd HH:mm:ss"));
```

1. 2019-05-25 09:00:00
2. 2019-04-25 09:00:00
3. 2019-5-25 9:0:0
4. 2019-4-25 9:0:0

<details>
<summary>答え</summary><div>
2
問14と同じくprototypeを使った問題。
ただし、Date.getMonthで返ってくる値は実際の月 - 1が返ってくるので、そのまま使うと4月になってしまいます。
</div></details>

# 問16 ①〜④の中でfalseが出力されるものの組み合わせとして正しいものを選べ。

```javascript
function f() {
    console.log(window == this);
}

var person = {
    f: function() {
        console.log(window == this);
    }
};

console.log(window == this); // ①
f();                         // ②
person.f();                  // ③
setTimeout(person.f, 1000);  // ④
```

1. ②、③
2. ①、②
3. ③
4. ②、③、④

<details>
<summary>答え</summary><div>
3
thisの問題。
オブジェクトのメソッド内ではthisはオブジェクト自身を指す。
それ以外は基本的にグローバルオブジェクトを指す。
[この記事の例がわかりやすいと思います。](https://qiita.com/mtoyopet/items/2fceef61b250e3917cb3)
ただし、オブジェクトのメソッドでもコールバック関数で呼ばれるときはグローバルオブジェクトを指す。
</div></details>

# 問17 以下のコードの実行結果として正しいものを選べ。

```javascript
var num1 = 1;
var num2 = new Number(2);
var array = [3, 4, 5];

function Person(name) {
    this.name = name;
}

var person = new Person("Mike");

console.log(
    typeof(num1),
    typeof(num2),
    typeof(array),
    typeof(person),
    typeof(person.name),
);
```

1. number Number Array Person string
2. number Number Array object string
3. number number object object string
4. number object object object string

<details>
<summary>答え</summary><div>
4
typeofの引数にプリミティブ型を指定する引数の型が、参照型を入れると全てobjectが返ります。
</div></details>


# 問18 以下のコードの実行結果として正しいものを選べ。

```javascript
var num1 = 1;
var num2 = new Number(2);
var array = [3, 4, 5];

function Person(name) {
    this.name = name;
}

var person = new Person("Mike");

console.log(
    num1 instanceof Number,
    num2 instanceof Number,
    array instanceof Array,
    person instanceof Person,
    person.name instanceof String,
);
```

1. エラー
2. true true true true true
3. true true false false true
4. false true true true false

<details>
<summary>答え</summary><div>
4
プリミティブ型以外であれば型を指定して判定できます。
</div></details>

# 問19 以下のコードの実行結果として正しいものを選べ。

```javascript
var num1 = 1;
var num2 = new Number(2);
var array = [3, 4, 5];

function Person(name) {
    this.name = name;
}

var person = new Person("Mike");

console.log(
    num1 instanceof Object,
    num2 instanceof Object,
    array instanceof Object,
    person instanceof Object,
    person.name instanceof Object,
);
```

1. false true true true false
2. true true true true true
3. false true true true true 
4. false false true true false

<details>
<summary>答え</summary><div>
1
こちらも18と同じです。
全ての参照型はObjectを継承します。
</div></details>

# 問20 ①〜④の中でHelloと出力されるものの組み合わせとして正しいものを選べ。

```javascript
Object.prototype.hello = "Hello";

var str = "String";
var num = new Number(1);
var array = [1, 2, 3];
var person = {name : "Kate"};

console.log(str.hello);    // ①
console.log(num.hello);    // ②
console.log(array.hello);  // ③
console.log(person.hello); // ④
```

1. ①、②、④
2. ③、④
3. ②、③、④
4. ①、②、③、④

<details>
<summary>答え</summary><div>
4
プリミティブ型でもラッパークラスのプロパティにアクセスできます。
</div></details>

# 参考文献
[JavaScriptリファレンス](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference)
[HTML5プロフェッショナル認定試験レベル2 サンプル問題](https://html5exam.jp/measures/lv2_1.html)
[JavaScriptのthisがよくわからないので徹底的に調べてできるだけわかりやすく解説してみる](https://qiita.com/mtoyopet/items/2fceef61b250e3917cb3)