jtk

【学習メモ】[Udemy] JavaScriptエンジニアのためのES6完全ガイド 勉強メモ その1

概要

【世界で 2 万人が受講】JavaScript エンジニアのための ES6 完全ガイド | Udemy を学習したのでメモしておきます。
動画内で図解を用いたくわしい解説や小テストがフェーズごとにあります。
こちらに記載しているコードは自分なりに発展させたものになります。

講座は基本的には ES5 までの書き方が分かっている人向けだと思いました。
ES5 ではこう書く必要があるけど、ES6 ではこう書けますよ。仕組みとしてはこういう考え方で処理されます。といった形で説明されています。

自分のような ES5 をまともに書けないけど、for 文って何、配列って何、といった超初級者向けでもない人だったらギリギリついていけるレベルに感じました。

またオリジナルは英語の動画ですが、ES6 でできることを網羅して解説するのが目的と思いますので、特定のメソッドや機能に関して完璧に解説されているものではないと思います。
パフォーマンス的にどうこいう、ということより、パッとコードを見た際に ES6 で書いたほうが見やすいですよね、などそのあたりがざっくりと感じられる人は気になるかもしれません。

その他参考

メソッド編

forEach

Array.prototype.forEach() - JavaScript | MDN

forを使う場合

var names = ["Taro", "Hanako", "Ichiro"];

// ここから for
for (var i = 0; i < names.length; i++) {
  console.log(names[i]); // "Taro" "Hanako" "Ichiro"
}

forEachを使う場合

// ここから forEach
names.forEach(function(name) {
  console.log(name); // "Taro" "Hanako" "Ichiro"
});

この場合 function(name) { console.log(name); } がコールバック関数となる。

var numbers = [1, 2, 3, 4, 5];
var sum = 0; // 合計を保持する変数

// ここから forEach
// 配列の一つ一つの数字を合計に足す
numbers.forEach(function(number) {
  sum += number;
});

// 合計を表示する
console.log(sum); // 15

匿名関数を使わず名前付きの関数を用意する場合

// ここから forEach
function adder(number) {
  sum += number;
}
// 配列の一つ一つの数字を合計に足す
numbers.forEach(adder);

// 合計を表示する
console.log(sum); // 15

map

Array.prototype.map() - JavaScript | MDN

forを使う場合

var numbers = [1, 2, 3];

// ここから for
var doubleNumbers = []; // 2倍にする数字を格納する変数。既存の配列は書き換えずに新しく用意したほうがよい
for (var i = 0; i < numbers.length; i++) {
  // numbers[i] = numbers[i] * 2
  doubleNumbers.push(numbers[i] * 2);
}

console.log(doubleNumbers); // [2, 4, 6]

mapを使う場合 この場合 numbers 配列は変更されず、結果の配列は新しく作成されている

// ここから map
var doubled = numbers.map(function(number) {
  return number * 2; // 戻り値として新しい配列に渡される
});

console.log(doubled); // [2, 4, 6]

mapは配列のなかの特定の値を引っ張るときなどに有効

var members = [
  { name: "Taro", gender: "male" },
  { name: "Hanako", gender: "female" }
];

// ここから map
// members配列からgenderのmale/femaleを引っ張ってきたい
var mapGenders = members.map(function(name) {
  return name.gender;
});

console.log(mapGenders); // ["male", "female"]

filter

Array.prototype.filter() - JavaScript | MDN

forを使う場合

var members = [
  { name: "Taro", gender: "male" },
  { name: "Hanako", gender: "female" },
  { name: "Ichiro", gender: "male" },
  { name: "Tomoko", gender: "female" }
];

// ここから for
var filterMembers = [];
for (var i = 0; i < members.length; i++) {
  if (members[i].gender === "female") {
    filterMembers.push(members[i]);
  }
}

console.log(filterMembers);

/*** 結果 ***
[[object Object] {
  gender: "female",
  name: "Hanako"
}, [object Object] {
  gender: "female",
  name: "Tomoko"
}]
*** 結果 ***/

filterを使う場合

// ここから filter
var filterMembers = members.filter(function(member) {
  return member.gender === "female";
  /*** 下記のようにif文にする必要はない ***
  if (member.gender === 'female') {
    return true;
  }
  ***/
});

console.log(filterMembers);

/*** 結果 ***
[[object Object] {
  gender: "female",
  name: "Hanako"
}, [object Object] {
  gender: "female",
  name: "Tomoko"
}]
*** 結果 ***/

複数の条件で絞り込みする

var members = [
  { name: "Taro", gender: "male", age: 30 },
  { name: "Hanako", gender: "female", age: 20 },
  { name: "Ichiro", gender: "male", age: 50 },
  { name: "Tomoko", gender: "female", age: 40 }
];

// ここから filter
// gender:'male' / age:30以上 の配列を絞り込む
var filterMembers = members.filter(function(member) {
  return member.gender === "male" && member.age >= 30;
});

console.log(filterMembers);

/*** 結果 ***
[[object Object] {
  age: 30,
  gender: "male",
  name: "Taro"
}, [object Object] {
  age: 50,
  gender: "male",
  name: "Ichiro"
}]
*** 結果 ***/

ブログのようなデータから関連するデータだけに絞り込みたい

var post = { id: 1, title: "投稿のタイトルです。" };
var comments = [
  { postId: 1, content: "コメント01" },
  { postId: 99, content: "コメント02" },
  { postId: 1, content: "コメント03" }
];

// ここから filter
// ID:1の投稿に紐づく投稿を取得する
function commentsForPost(post, comments) {
  return comments.filter(function(comment) {
    return comment.postId === post.id;
  });
}

console.log(commentsForPost(post, comments));

/*** 結果 ***
[[object Object] {
  content: "コメント01",
  postId: 1
}, [object Object] {
  content: "コメント03",
  postId: 1
}]
*** 結果 ***/

find

Array.prototype.find() - JavaScript | MDN

ある配列から自分の探したい要素を引っ張ってくる forの場合

var members = [
  { name: "Taro", age: 30 },
  { name: "Hanako" },
  { name: "Ichiro", age: 50 },
  { name: "Tomoko" }
];
var findMembers;

// ここから for
for (var i = 0; i < members.length; i++) {
  if (members[i].name === "Ichiro") {
    findMembers = members[i];
    break;
  }
}

console.log(findMembers);

/*** 結果 ***
[object Object] {
  age: 50,
  name: "Ichiro"
}
*** 結果 ***/

findの場合 filterとは違い、findは 1 番目に見つかった要素が返される。

// ここから find
var findMembers = members.find(function(member) {
  return member.name === "Ichiro";
});

console.log(findMembers);

/*** 結果 ***
[object Object] {
  age: 50,
  name: "Ichiro"
}
*** 結果 ***/

Ichiro を探したい

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

var members = [new Member("Taro"), new Member("Hanako"), new Member("Ichiro")];

var findMembers = members.find(function(member) {
  return member.name === "Ichiro";
});

console.log(findMembers);

/*** 結果 ***
[object Object] {
  name: "Ichiro"
}
*** 結果 ***/

コメントに紐づく投稿を探す

var posts = [{ id: 1, title: "古い投稿" }, { id: 2, title: "新しい投稿" }];
var comment = { postId: 2, content: "いいね!" };

function postForComment(post, comment) {
  return posts.find(function(post) {
    return post.id === comment.postId;
  });
}

console.log(postForComment(posts, comment));

/*** 結果 ***
[object Object] {
  id: 2,
  title: "新しい投稿"
}
*** 結果 ***/

every,some

Array.prototype.every() - JavaScript | MDN Array.prototype.some() - JavaScript | MDN

forの場合

var members = [
  { name: "Taro", age: 30 },
  { name: "Hanako", age: 20 },
  { name: "Ichiro", age: 50 },
  { name: "Sachiko", age: 10 }
];

// ageが20以上のmemberを探す
var allMembersAdult = true; // すべての人が20歳以上の場合のフラグ
var someMembersAdult = false; // だれか一人でも20歳以上の場合のフラグ

// ここから for
for (var i = 0; i < members.length; i++) {
  var member = members[i];
  if (member.age < 20) {
    allMembersAdult = false; // すべての人が20歳以上の場合
  } else {
    someMembersAdult = true; // だれか一人でも20歳以上の場合
  }
}

console.log(allMembersAdult); // false
console.log(someMembersAdult); // true

everysomeの場合

// ここから every
// 論理積を取る(trueが全部である)
allMembersAdult = members.every(function(member) {
  return member.age >= 20;
});

console.log(allMembersAdult); // false

// ここから some
// 論理和を取る(trueがひとつでもある)
someMembersAdult = members.some(function(member) {
  return member.age >= 20;
});

console.log(someMembersAdult); // true

すべて名前の文字数は 5 文字以上か調べる

var names = ["Taro", "Hanako", "Ichiro", "Tomoko", "Jiro"];

// すべて名前の文字数は5文字以上か調べる
allNamesMoreThan5 = names.every(function(name) {
  return name.length >= 5;
});

console.log(allNamesMoreThan5); // false

// どれか名前の文字数は5文字以上か調べる
someNamesMoreThan5 = names.some(function(name) {
  return name.length >= 5;
});

console.log(someNamesMoreThan5); // true

every,someの使いどころ

function Field(value) {
  this.value = value;
}

Field.prototype.validate = function () {
  return this.value.length > 0;
}

var username = new Field('my_username');
var password = new Field('my_password');
var birthday = new Field('my_password');

// username.validate() && password.validate() && birthday.validate();
// 上記のように書くと無限に増える...
// こういうときにeveryを使う

var fields [
  username,
  password,
  birthday
];

var formIsValid = fields.every(function(field) {
  return field.validate();
});

if (formIsValid) {
  // サーバーにリクエストを投げる
} else {
  // エラーを表示する
}

reduce

徐々に配列に何個もあるものが 1 個に集約していく動きをするのが reduce forの場合

var numbers = [10, 20, 30];
var sum = 0;

// for文 ここから
for (let i = 0; i < numbers.length; i++) {
  sum += numbers[i]; // 60
}

console.log(sum); // 60

reduceの場合

// reduce ここから
var sum = numbers.reduce(function(sum, number) {
  return sum + number; // 60
}, 0); // ここの第2引数の0が初期値、-100でも100でもなんでもOK

console.log(sum); // 60

初期値に数字ではないものを入れる場合

var members = [{ name: "Taro" }, { name: "Hanako" }, { name: "Ichiro" }];

// ['Taro','Hanako','Ichiro'] という配列を作りたい
// mapを使うとやりやすい
var reduceMembers = members.reduce(function(previous, member) {
  previous.push(member.name);
  return previous;
}, []); // 初期値として空の配列を入れる

console.log(reduceMembers); // ["Taro", "Hanako", "Ichiro"]