前書き
JavaScriptの問題集がないか探していたところ、こちらを見つけました。
もりたけんじさんが作成されたようです。
ざっと見てみたところかなり勉強になりそうなので、こちらに掲載されている問題を解きつつ、私及び初心者向けにさらに深く解説を載せていこうと思います。※許可を得ています。
解いたら随時追加していきます。
身についたこと
大体上から順番
Object.assign()
slice()
forEach()
Array.isArray()
-
typeof
演算子 -
void
演算子 -
for...in
とhasOwnProperty()
join()
delete
sort()
- ジェネレータ
- スプレッド構文
splice()
-
splice()
,slice()
-
join()
,split()
Object.create()
prototype
練習問題1
問題
const a = { a: 'a' }とconst b = { b: 'b' } をマージしたc を出力してください e.g{ a:'a', b:'b' }
私の解答
const a = {a: 'a'};
const b = {b: 'b'};
const c = {...a, ...b};
console.log(c);
// --> { a: 'a', b: 'b' }
正解。
スプレッド演算子を使用した方法。
配列にしろオブジェクトにしろスプレッド構文はshallow copyなので、ネストしている場合は注意が必要です。
引用元⇩
別解
const c = Object.assign({}, a, b);
Object.assign()メソッドを使用した方法。
こちらもShallow Copy
である点に注意が必要。
詳しくは⇩
実験してみた
const originObj = {a:1, b:{a:2}};
const assignObj = Object.assign({}, originObj);
console.log(assignObj);
// --> { a: 1, b: { a: 2 } }
originObj.b.a = 3;
console.log(assignObj);
// --> { a: 1, b: { a: 3 } }
originObj.a = 4;
console.log(assignObj);
// --> { a: 1, b: { a: 3 } }
assignObj.b.a = 5;
console.log(originObj);
// --> { a: 4, b: { a: 5 } }
console.log(assignObj);
// --> { a: 1, b: { a: 5 } }
assignObj.a = 6;
console.log(originObj);
// --> { a: 4, b: { a: 5 } }
console.log(assignObj);
// --> { a: 6, b: { a: 5 } }
練習問題2
問題
const arry = ['aa','bb','cc','dd','ee','ff','gg'];
のdd,ee,ffを新たな配列として返してください
私の解答
const arry2 = ['aa', 'bb', 'cc', 'dd', 'ee', 'ff', 'gg'];
const ansArry2 = arry2.slice(3,3);
console.log(ansArry2);
// --> []
間違い。
恐らくsplice
メソッドの、
let 切り取られた配列 = 元の配列.splice( 開始位置, 長さ, [, 要素追加1, 要素追加2, ... ] );
// []内は省略可
と混同していた。
splice
メソッドはslice
メソッドと違い、元の配列に対して影響を及ぼす。
模範解答
const newArry = arry.slice(-4,-1);
//or
const newArry = arry.slice(3,-1);
let 切り取られた配列 = 元の配列.slice( [ 開始位置, 終了位置 ] );
// []内は省略可
と書く。
負の数を引数に持たせると、絶対値が後ろから数えて何番目か(0スタート)を表す。
参考:独習JavaScript
練習問題3
問題
['a','b’] の要素をconsole出力してください e.g 'a'と'b'
私の解答
const arry3 = ['a', 'b'];
arry3.forEach((element)=>{
console.log(element);
})
// --> a
// --> b
正解。模範解答とほぼ一致したため、模範解答は省略
forEach
メソッドを用いた。
練習問題4
問題
['a', 'b']の各要素にindex値を足した文字列を出力してくださいe.g 'a0'と'b1'
私の解答
const arry4 = ['a', 'b'];
arry4.forEach((element, index)=>{
console.log(`${element}${index}`);
})
// --> a0
// --> b1
正解。
forEach
メソッドとテンプレートリテラルを用いた。
模範解答はテンプレートリテラルでなく、
console.log(element+index);
としていた。
練習問題5
問題
任意の変数名の[1,2]を定義して配列かどうかを評価してください e.g true
私の解答
const arry5 = [1, 2];
console.log(arry5.isArray());
// --> エラー
不正解。分からなかった。
模範解答
Array.isArray(arry5);//true
Array.isArray()
メソッドは、与えられた値がArray
かどうかを返す。
isArray()
が標準組み込みオブジェクトArray
のメソッドであることを理解していなかった。
練習問題6
問題
//1
if (typeof x === 'undefined') {
???
}
//2
if(x === undefined){
???
}
変数xが定義されていない場合上の1、2は実行されますか?
私の解答
分からない
解答
//1は実行される
//2は実行されない(ReferenceError)
解説
未評価のオペランドの型を示す文字列を返します。
試しに
if(typeof x === undefined){
console.log('1');
}
console.log('2');
を実行してみると、2
とだけ出力された。
//2 が実行されないのは、定義されていない変数について評価しようとしたことが原因でエラーとなったから。
練習問題7
問題
//1
let x;
if (x === void 0) {
}
//2
// 直前まで y は宣言されていない
if (y === void 0) {
}
1,2はそれぞれ実行されますか
私の解答
//1 は実行される
//2 は実行されない。
解説
正解。
void
演算子は必ずundefinedを返す。
JavaScriptにおけるvoid 0
が持つ意味に関する参考記事
練習問題8
問題
const obj = {
key: 'aa',
key2: 'bb'
}
の中のkeyとvalueを自身のプロパティのみ全て出力しなさい
私の解答
分からなかった。
模範解答
const obj = {
key: 'aa',
key2: 'bb'
}
for (key in obj){
if(obj.hasOwnProperty(key)){
console.log(key, obj[key])
}
}
//key aa
//key2 bb
//or use Object.values, Object.keys
解説
for...in
文は、キーが文字列であるオブジェクトの列挙可能プロパティすべてに対して、継承された列挙可能プロパティも含めて反復処理を行う。
また、hasOwnProperty()
メソッドは、オブジェクト自身が(継承されていない)指定されたプロパティを持っているかどうかを示す真偽値を返す。
似たものにin
があるが、この違いは、
in
はprototypeチェーンをさかのぼるのに対し、hasOwnProperty()
はさかのぼらない。
参考↓
練習問題9
問題
こちらの ['a', 'b', 'c'] 配列の中の全ての要素を結合し、1つの文字列として出力してください。
私の解答
arry9.join('');
// --> abc
解説
正解。join()
メソッドは、配列(または配列風オブジェクト)の全要素を順に連結した文字列を新たに作成して返す。
配列風オブジェクトとは、例えば以下のようなもの。
<body>
<ul>
<li class="nodelist">a</li>
<li class="nodelist">b</li>
<li class="nodelist">c</li>
</ul>
<script>
console.log(document.getElementsByClassName("nodelist"));
console.log(document.getElementsByTagName("li"));
</script>
</body>
実行すると、
のようになる。他にもarguments
オブジェクトなどがある。
Array.from()
メソッドを用いることで、配列風オブジェクトからシャローコピーされた新しい配列を返すことができる。
練習問題10
問題
こちら
x = 43
let y = 3
の2つの変数。deleteできるのはどちらですか?
私の解答
deleteがなんだか分からず、解けなかった。
模範解答
x = 43;
delete x
//true //暗黙に定義されたglobale変数なので
delete y
//false //削除できない
解説
delete
演算子自体が初耳だったので、調べてみた。
JavaScript の delete 演算子は、オブジェクトからプロパティを削除します。同じプロパティへの参照がそれ以上保持されていない場合は、自動的に解放されます。
また、
delete expression
expression は下記のように、プロパティへの参照として評価されるべきものです。
delete object.property delete object['property']
オブジェクトのプロパティを削除するために使うことが推奨されているようだ。
練習問題11
問題
let arry =[
{id:1,name:'morita'},
{id:2,name:'kenji'},
{id:4,name:'uro'},
{id:3,name:'ken'}
];
をid番号が若い順にソートしたオブジェクトを含む配列を出力してください
私の解答
let arry =[
{id:1,name:'morita'},
{id:2,name:'kenji'},
{id:4,name:'uro'},
{id:3,name:'ken'}
];
let tmp;
for(let i=0;i<=arry.length-2;i++){
if(arry[i].id>arry[i+1].id){
tmp = {...arry[i]};
arry[i] = {...arry[i+1]};
arry[i+1] = {...tmp};
}
}
console.log(arry);
// -->
[
{ id: 1, name: 'morita' },
{ id: 2, name: 'kenji' },
{ id: 3, name: 'ken' },
{ id: 4, name: 'uro' }
]
解説
正解。ではあるが、長い。
i
番目とi+1
番目のオブジェクトのidを比べ、i
番目の方が大きかったら入れ替えるという記述。
スプレッド構文
はオブジェクトに対しても使える。
模範解答
arry.sort(function(a,b){
return a.id > b.id
})
または
arry.sort(function(a,b){
if(a.id > b.id) return 1;
if(a.id < b.id) return -1;
});
sort()
メソッドを使ったもの。
compareFn(a, b) の返り値 |
ソート順 |
---|---|
>0 |
a をb の後に並べる |
<0 |
a をb の前に並べる |
===0 |
a とb の元の順序を維持する |
関数compareFn
が省略された場合、すべての配列要素は文字列に変換される。
const tesarr = [1, 5, 2, 4, 3, 10, 246];
tesarr.sort();
console.log(tesarr);
// --> [1, 10, 2, 246, 3, 4, 5]
練習問題12
問題
a, bの変数はデフォルトとしてaは5、bは7を持ち、aに1を代入してconsole出力してください。
私の解答
「デフォルトとして」の意味が分からない。
let a=5; let b=7; a=1;
console.log(a,b);
模範解答
const [a=5, b=7] = [1];
// or
const {a = 5, b = 7} = {a: 1};
デフォルトとして値を持たせたいので、単に代入している私の解答では間違いっぽい。
模範解答のように配列かオブジェクトとして宣言して代入することで、宣言と同時に値が与えられる
-> デフォルトとして値を持つ?
練習問題13
問題
next()を実行しただけ返り値が1増える関数を定義してください
私の解答
ジェネレータだ...
const increment = function*(num){
while(1){
yield num+=1;
}
}
let doInc = increment(0);
console.log(doInc.next().value);//1
console.log(doInc.next().value);//2
console.log(doInc.next().value);//3
解説
正解。
ジェネレータ構文自体は忘れていたので、私の記事を参考にしつつ解いた。
ジェネレータを扱う際はnextメソッドを実行すると、前のyield地点から次のyieldかreturnまで処理が進む
という前提が大事になりそう。
模範解答
const setUp = function(){
let count = 0;
return function(){
return (count += 1);
}
};
const next = setUp(); // ①
next();//1
next();//2
next();//3
ジェネレータを使っていなかった。
①
setUp()
で関数setUp
を実行し、変数count
を宣言、初期化する。
返り値となる無名関数を変数next
に格納し、次回以降はnext()
だけで、その無名関数部分のみが実行される(変数count
の再宣言、代入は行われない)仕組みと考えた。
実際に、console.log(next);
とすると、
f(){
return (count += 1);
}
となった。
練習問題14
問題
fun(1,2,3)を実行したら引数が全て配列で返る関数funを定義しなさい
私の解答
const fun = (...arr) => {
console.log(arr);
}
fun(1, 2, 3);
解説
間違い。問題文は配列で返る関数を定義しなさい
と言っているので、'return arr;'としなければいけなかった。
...arr
はたびたび登場しているがスプレッド演算子によるもの。この場合は引数をまとめて配列に格納してくれる便利なもの。
模範解答
function fun(){
return Array.from(arguments)
}
// or
function fun (...arg){
return arg;
}
Array.from()
メソッド
はこちら
2個目の解答は、アロー関数を用いることでかなり記述を減らせそう。
const fun = (...arg) => arg; //ok
練習問題15
問題
配列
const array = ['a1','a2','a3','a4','a5']
の0〜2番目の要素をそれぞれ
red, green, yellow
に置き換えて配列にしてください。また実行した際の返り値を教えてください
私の解答
何らかの配列のメソッドを使うんだろうとは思ったが、思いつかなかったので参考書を見て解いた。
const array = ['a1','a2','a3','a4','a5'];
let arr2 = array.splice(0, 3, 'red', 'green', 'yellow');
console.log(array); // --> [ 'red', 'green', 'yellow', 'a4', 'a5' ]
console.log(arr2); // --> [ 'a1', 'a2', 'a3' ]
解説
splice()
メソッドによるもの。
splice() メソッドは、その場で既存の要素を取り除いたり、置き換えたり、新しい要素を追加したりすることで、配列の内容を変更します。
模範解答と一致した。
練習問題16
問題
const array = ['a1','a2','a3','a4','a5']
のインデックス2〜4の要素を取り出し、 配列として出力しなさい。
実行された後のarrayの要素を教えてください
私の解答
const array = ['a1', 'a2', 'a3', 'a4', 'a5'];
console.log(array.splice(2,3));
// --> [ 'a3', 'a4', 'a5' ]
console.log(array);
// --> [ 'a1', 'a2' ]
模範解答
const array = ['a1','a2','a3','a4','a5']
const newArray = array.slice(1,4);
newArray
//['a2', 'a3', 'a4']
array
//['a1','a2','a3','a4','a5']
解説
インデックス2~4て添え字のことじゃないんかい!
問題文の意図は伝わっていなかったが、間違ったことはしていないと思う。
splice()
メソッド
slice()
メソッド
引数の違い、元の配列を操作するか否かに注意が必要。
練習問題17
問題
const array = ['a1','a2','a3','a4','a5']
の全ての要素を"/"で結合した文字列を出力し、
さらにその文字列を'/'区切りで配列に直してください
私の解答
const array = ['a1','a2','a3','a4','a5'];
const text = array.join('/')
console.log(text);
// --> a1/a2/a3/a4/a5
const newArray = text.split('/');
console.log(newArray)
// --> [ 'a1', 'a2', 'a3', 'a4', 'a5' ]
解説
正解。join()
メソッドとsplit()
メソッドを使ったもの。
join()メソッド
引数を省略すると、,
で連結される。
split()メソッド
第二引数に自然数を持たせることができ、分割する回数に制限を与えられる。
練習問題18
問題
配列['おはよう','こんにちは','おやすみなさい']の要素がランダムに出力される関数を書いてください。
(配列に要素が追加される事を仮定してたものにしてください)
私の解答
const greeting = ['おはよう', 'こんにちは', 'こんばんは'];
let rand = Math.floor(Math.random() * (greeting.length));
console.log(greeting[rand]);
// --> こんにちは
解説
正解。
greeting.length
によって乱数の幅を設定しているので、新しく配列の要素が追加されても対応してくれるようになっている。
変数rand
をlet
で宣言したが、const
でよかった。
乱数を生成したいときによく参考にするサイト↓
練習問題19
問題
Object.createで空のオブジェクトを作成し、値が1のプロパティpを出力してください
私の解答
ぜんっっっっぜんわからん
模範解答
const obj = Object.create({}, {p: {value: 1}});
obj.p //1
解説
Object.create()
メソッドを用いたもの(問題文で指示があるが)。
Object.create()
メソッドは、
- 第一引数に、新たに生成されるオブジェクトのプロトタイプになるべきオブジェクト
- 第二引数に、新たに生成されるオブジェクトに追加されるプロパティ
の2つの引数を持つ(第二引数は省略可能)。
練習問題20
問題
コンストラクタWhoの初期化時に'morita'(String)を渡しインスタンスプロパティnameに代入、
インスタンスメソッドgetNameの返り値がWho.prototype.name値になるいわゆる「classのようなもの」を作成してください
※インスタンスメソッドはprototypeに代入してください
模範解答
function Who(name){
this.name = name;
};
Who.prototype.getName = function(){
console.log('Myname is ' + this.name);
};
let o = new Who('morita');
o.getName()
解説
結果出来上がっているものは、以下の記述と同じようなものか。
class Who {
constructor(name){this.name = name;}
getName(){console.log('My name is ' + this.name);}
}
const o = new Who('morita');
o.getName();
function Who (name) {
this.name = name;
this.getName = function(){
console.log('My name is ' + this.name);
}
}
この記事を見ると、メモリの節約のためになるべくプロトタイプ拡張を用いた方が良いらしい
練習問題21
問題
浅いコピー(shallow copy)と深いコピー(deep copy)の違いを説明してください
私の解答
シャローコピーはアドレスをコピーするのに対し、ディープコピーはそのアドレスが格納する値をコピーする。
模範解答
シャローコピーはプロパティ値や要素値だけのコピーでその先の参照まではコピーしない。
ディープコピーはコピー元とコピー先が別のオブジェクトを参照していること。プロパティが別のオブジェクトを参照していれば参照先のオブジェクトも含めてコピーします。deepcopyが必要な場面はない。自分で実装する必要がある。
解説
私の解答は言いたいことは合っているがアドレスという単語がJSになかった。プロパティ値というべきか。
練習問題21
問題
下記
let array = ['e','a','k','B','c'];
array.sort();
を実行した結果を答えてください
私の解答
['B', 'a', 'c', 'e', 'k']
解説
正解。
大文字の方が文字コードは小さい。