JavaScriptに関するクイズを自分向けに作成してみた

2022/03/12に公開1

こんにちは。株式会社プラハCEOの松原です

What is this?

最近自分が使っている技術の基礎を固めることの大切さを改めて感じてJSの基礎学び直した際、「ただ情報をインプットしても忘れるし、読みながらアウトプットしても忘れそうだな...」と不安になったので

  • 学びながら未来の自分に向けてクイズを作成する
  • クイズを1ヶ月おきに解く
  • 100点を連続で取れない限りクイズを繰り返す

みたいな学習方法なら記憶に定着しやすいのではないかと考え、自分向けのクイズを作ってみました。せっかくなら他の人も回答できた方が楽しいかな?と思ったので公開してみます。作問自体が良い勉強になるし、これは今後も応用できそうな学習方法だな...(Chrome上でエンジンのバージョンV8 9.8.177.11で実行しながら作ったので、環境が違うと答えが変わることも)

nullとundefined

Q: typeof

console.log(typeof null) // 何が出力される?
console.log(typeof undefined) // 何が出力される?

Q: undefinedはグローバル?

undefined in this // 何が出力される?
null in this // 何が出力される?

プリミティブとオブジェクト

Q: 同値?等値?

1 == '1' // true? false?
1 === '1' // true? false?
0 == null // true? false?
0 === null // true? false?
null == undefined // true? false?
nul === undefined // true? false?

Q: プリミティブのinstanceof

3 instanceof Number // true? false?
'foo' instanceof String // true? false?
new Number(3) instanceof Number // true? false?

Q: オブジェクトのinstanceof

let HogeConstructor = function Hoge() {}
let hc = new HogeConstructor()

hc instanceof HogeConstructor // true? false?

hc.__proto__ = {}
hc instanceof HogeConstructor // true? false?

Q: in と hasOwnPropertyの違い

let a = {name: 'hoge'}

'name' in a // true? false?
'toString' in a // true? false?
a.hasOwnProperty('toString') // true? false?

Q: Objectのpropertyはiterableか否か

let CustomConstructor = function() {
    this.a = 'a'
}
let CustomInheritedConstructor = function() {
    this.b = 'b'
}
CustomInheritedConstructor.prototype = new CustomConstructor()
let cic = new CustomInheritedConstructor()
cic.c = 'c'

console.log(cic.propertyIsEnumerable('a')) // true?false?
console.log(cic.propertyIsEnumerable('b')) // true?false?
console.log(cic.propertyIsEnumerable('c')) // true?false?

for (var key in cic) {
  console.log(key)
} // -> 何が出力される?for...inとpropertyIsEnumerableは何が違う?

Object.prototype.fuga = 'fuga'
'hoge'.fuga // 何が出力される?それともundefined...?

for (var key in cic) {
  console.log(key)
} // -> 先程のfor...inと比較して変化は起きる?

Q: isNaN()

isNaN('hoge') // true?false?
isNaN(1) // true?false?
isNaN(true) // true?false?
isNaN(null) // true?false?
isNaN(undefined) // true?false?
isNaN('') // true?false?

Q: parseInt()

// 何が出力される?
parseInt('FF',16)
parseInt('11111111',2)
parseInt('255')
parseInt('0xFF') // ちょっと実行環境に依存する
parseInt(255)
parseInt(255, NaN)
parseInt('0xFF', NaN) // ちょっと実行環境に依存する

Q: オブジェクト同士の比較

JSON.stringify({a: 1, b: 2}) === JSON.stringify({a: 1, b: 2}) // これは何がいけない?
JSON.stringify({a: 1, b: 2}) === JSON.stringify({b: 2, a: 1}) // 例えばこうなったら...?

Q: プリミティブ?オブジェクト?

let n1 = new Number(1)
let n2 = Number(1)

console.log(typeof n1) // 何が出力される?
console.log(typeof n2) // 何が出力される?

Q: コピー?参照?

let s = 'hoge'
let scopy = s
s = null

console.log(scopy) // null?それとも'hoge'?

let o = new Object({name: 'hoge'})
let ocopy = o

ocopy.name = 'fuga'
console.log(o) // {name: 'fuga'}?それとも{name: 'hoge'}?

o = null
console.log(ocopy) // nullになる?

Q: 元のオブジェクトはどうなる?

function hoge(obj) {
    obj.hoge = 'hoge'
}
function fuga(obj) {
    obj = {fuga:'fuga'}
}

var obj = {}

hoge(obj) // objはどうなる?
fuga(obj) // objはどうなる?

this

Q: 継承した際のsuperについて

class Base {}
class A extends Base {}
class B extends Base {
  constructor() {
    return {a: 5};
  }
}
class C extends Base {
  constructor() {}
}

new A(); // インスタンス化できる?
new B(); // インスタンス化できる?
new C(); // インスタンス化できる?

Q: ネストされたobjectの中におけるthisの挙動

var obj = {prop: 37};

function callprop() {
  return this.prop;
}

obj.callprop = callprop;
obj.callprop(); // これは何が返る?

obj.child = {childCallprop: callprop, prop: 300000}
obj.child.childCallprop(); // これは何が返る?

let callprop2 = () => {
    return this.prop // callpropをアロー関数で定義してみる
}

obj.callprop = callprop2;
obj.callprop(); // これは何が返る?

Q: prototypeの中におけるthisの挙動

var Person = function() {
    this.hoge = 'hoge from constructor'
}
Person.prototype.getHoge = function() {
    return this.hoge
}
Person.prototype.hoge = 'hoge from prototype'

Person.prototype.getHoge() // 何が出力される?

var p = new Person()
p.getHoge() // 何が出力される?

p.hoge = 'hoge from instance'
p.getHoge() // 何が出力される?

Q: strict this

function f2() {
  'use strict';
  console.log(this);
}
f2() // 何が出力される?

function f2() {
  console.log(this);
}
f2() // 何が出力される?

var f2new = f2.bind({name: 'hoge'})
f2new() // 何が出力される?

Q: アロー関数のthis

let calculator = {
  value: 0,
  add: (values) => {
    this.value = values.reduce((a, v) => a + v, this.value);
  },
};
calculator.add([1, 2, 3]);
console.log(calculator.value); // 何が返ってくる?
const adder = {
  add: (values) => {
    this.value = values.reduce((a, v) => a + v, this.value);
  },
};
let calculator = {
  value: 0
};
adder.call(calculator, [1, 2, 3]); // 何が返ってくる?

Q: ついでにuse strictも

let f = function() {
    'use strict';
    piyo = 'piyo';
}
f() // 何が起きる?

Q: callとapplyを使った時のthisの挙動

var a = 'Global';
function whatsThis() {
  return this.a;
}

whatsThis(); // どうなる?
whatsThis.call({a: 'hoge'}) // どうなる?
whatsThis.apply({a: 'hoge'}) // どうなる?

Q: callとapplyって何が違うの?

whatsThis.call({a: 'hoge'}) // 下とやってること
whatsThis.apply({a: 'hoge'}) // 同じじゃね?どんな時に使い分けるの?

Q: アロー関数のthisはどのタイミングで確定するのか

var obj = {
  bar: function() {
    var x = (() => this);
    return x;
  }
};

var fn = obj.bar();
fn() // これはwindowと一致する?それともobj?

var fn2 = obj.bar;
fn2()() // これはwindowと一致する?それともobj?

Q: newを使わずコンストラクタを呼び出したら何が起きるのか

var Hoge = function Hoge(name) {
    this.name = name
}
let h = new Hoge('hoge name') // コンストラクタとして使える
Hoge('hoge name') // これは何が起きる?windowには何が起きる?

スコープ

Q: if,forはスコープを持つ?

(function hoge() {
    v = 'hoge'
})() // -> window.vはどうなる?

if (true) {
  v = 'if'
} // -> window.vはどうなる?

Q: スコープはどの時点で確定する?

function hoge() {
    var name = 'hoge'
    return function() {
        console.log(name)
    }
}
let func = hoge()
func() // 何が出力される?

function fuga(f) {
    var name = 'fuga'
    f()
}
fuga(func) // 何が出力される?

Q: クロージャ

let closure = function () {
    var counter = 0
    return function() {
        counter++
        console.log(counter)
    }
}()

closure() // 何が返る?
closure() // 何が返る?

Q: クロージャ内で参照を共有

var log = function() {
    var array = [];
    var i;
    for (i = 0; i<3; i++) {
        array[i] = function() {console.log(i)}
    }
    return array;
}()

log[0]() // 何が出力される?
log[1]() // 何が出力される?
log[2]() // 何が出力される?

// 0,1,2と出力させるためには何を変える必要がある?(どうすればarrayに含まれる関数の中のiのスコープを狭められる?)

グローバルオブジェクト(ブラウザ編)

Q: window[0]って何?

for (key in window) {
  console.log(key)
}
// -> 0,1...が出力される。0と1って何?window[0]とかwindow[1]って何?

Q: グローバルプロパティとグローバル変数の違い

var a = 'a'
b = 'b'

console.log(window.a) // 何が出力される?
console.log(window.b) // 何が出力される?

delete window.a // 何が起きる?
delete window.b // 何が起きる?

Q: グローバルthis

this === window // true?false?

プロトタイプチェーン

Q: __proto__って何?

function Hoge() {}
Hoge.prototype.a = 'a'
var h = new Hoge()
h.a = 'a of instance'

console.log(h.a) // 何が出力される?
console.log(h.__proto__.a) // 何が出力される?
console.log(h.__proto__ === h.constructor.prototype) // true?false?
console.log(h.__proto__ === Hoge.prototype) // true?false?

Q: プロトタイプチェーンの行き着く先

function Hoge() {}
var h = new Hoge()

console.log(h.a) // 何が出力される?

Object.prototype.a = 'a'
console.log(h.a) // 何が出力される?

Function.prototype.a = 'b'
console.log(h.a) // 何が出力される?
console.log(Hoge.a) // 何が出力される?hとHogeは__proto__にどんな違いがある?

Q: prototypeを丸ごと置き換えた時の挙動

function Hoge() {}
Hoge.prototype.a = 'a'
var h = new Hoge()
Hoge.prototype = {a: 'a new!'}
var h2 = new Hoge()

console.log(h.a) // 何が出力される?
console.log(h2.a) // 何が出力される?

Hoge.prototype.a = 'a final'
console.log(h.a) // 何が出力される?
console.log(h2.a) // 何が出力される?
console.log(h.constructor.prototype.a) // 何が出力される?constructor.prototypeと__proto__はprototypeを丸ごと入れ替えた時どんな風に異なる挙動を示す?

random gotchas

function hoge() {
    return
    {name: 'hoge'}
}
var h = hoge() // hには何が入る?

参考にした記事や書籍

Common JavaScript "gotchas"
mdn
開眼!JavaScript
Common JavaScript gotchas

アガルートテクノロジーズ/PrAha

Discussion