シリーズ概要
Phase 1 のまとめ
- Parcel で module system が使えるようになった。
- Parcel で Babel の処理をしてくれるので、ES2015+ syntax で JS を書くことができるようなった。
- Parcel が勝手に JSX も処理してくれるので React コンポーネントを JSX で書けるようになった。
- Prettier でコードが成形できるようになった。
Phase 2
モダンなパラダイムで JavaScript を書く
- var, let を書かないで、ほぼ全部 const にする
- immutable にする
- そのためには functional programming に則っていく必要あり。
map, reduce 等をうまく使う。
Phase 3 の展望
非同期処理をモダンに書く
- Callback の根絶
- Promise の理解
- async / await を使う
- redux/vuex 関係でも async/await を使う
Phase 4 の展望
Virtual DOM を用いた View ライブラリの活用
- ReactJS
- VueJS
- Redux/Vuex
モダンなパラダイムで JavaScript を書く
- 全て const を使う(くらいの気持ちで)
- Immutable にする(Object の property, Array の要素を変更しない)
- Functional Programming を意識する
Immutable にすることを意識すれば、結果として上記三つを満たすことになる。
const を基本的に使う
- 全て const でかく(くらいの気持ちで)
- var は使うケースはないと考えていい
- let もほぼほぼ使わない
変数を宣言する場合には、基本的に const
を使用する。const
は再代入を受け付けない。
関数の場合
関数を再代入する必要があるケースはほぼない。そのため const
を使う。
もし関数を再代入する必要があるとすれば、その構造自体を再検討する必要がある。
// 関数宣言 (function declaration) を使用した場合
// 関数の巻き上げ (function hoisting) が起きてしまう
// これはしない方がいい
// 可読性が低いため
func1()
function func1() {
console.log('func1')
}
// 関数式(function expression) で定義した場合
// 関数の巻き上げは起きない
// 望ましい
try {
func2()
} catch (err) {
console.error(err.message)
}
var func2 = function() {
console.log('func2')
}
// (特殊なケースを除けば)
// 関数を再代入することは避けた方がいいので
// 再代入を禁止する const を使用する方が良い
// また arrow function を使った方がよい
const func3 = () => {
console.log('func4')
}
func3()
// async を使いたい場合には、
// 以下のように書けばいい
const promiseFunc = val => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(val)
}, 1000)
})
}
const func5 = async () => {
const val = await promiseFunc('start promise')
console.log(val)
}
func5()
配列に push していくパターンもやめる
(どちらかというと後ほど取り上げる immutable のテーマだが)
// よくみるがあまり良くない例
// からの配列を宣言しておいて、後からそれに追加するパターン
var array1 = [1, 2, 3, 4]
var array2 = []
for (var i = 0; i < array1.length; i++) {
array2.push(array1[i] + i)
}
console.log(array2)
// map を使えば全て const で宣言できる
const array3 = [1, 2, 3, 4]
const array4 = array3.map((o, index) => o + index)
console.log(array4)
Object の場合
(これも配列の場合と同じく、immutable が主テーマだが)
const obj1 = { name: 'nakanishi', id: 1 }
// property を書き換える場合には次のようにする
// 実際には書き換えているのではなく、新しいオブジェクトを作成している
const obj2 = { ...obj1, name: 'sasaki' }
console.log(obj1, obj2)
Immutable にする
- Object のプロパティを変更しない
- Array の要素を変更しない
- 新しい object, array を生成する
// object を deep freeze させる
// => mutation が起きる場合、エラーを吐く
import deepFreeze from 'deep-freeze'
// object の場合
const obj1 = { name: 'nakanishi', id: 1 }
deepFreeze(obj1)
// property を書き換える場合には次のようにする
// 実際には書き換えているのではなく、新しいオブジェクトを作成している
const obj2 = { ...obj1, name: 'sasaki' }
console.log(obj1, obj2)
// deepFreeze させているので、
// property を書き換えるとエラーが出る
try {
obj1.name = 'sasaki'
} catch (err) {
console.error(err.message)
}
// 配列の場合
const array1 = []
deepFreeze(array1)
// 配列の要素を書き換える場合には次のようにする
// 実際には書き換えているのではなく、新しい配列を作成している
const array2 = [...array1, 'test']
console.log(array1, array2)
try {
// deepFreeze させているので、
// 配列の要素を書き換えるとエラーが出る
array1.push('test')
} catch (err) {
console.error(err.message)
}
const array3 = [1, 2, 3]
try {
// deepFreeze させているので、
// 配列の要素を書き換えるとエラーが出る
array1[0] = 'test'
} catch (err) {
console.error(err.message)
}
// Object の property を削除する方法
const person = {
name: 'John',
password: '123',
age: 28,
}
deepFreeze(person)
// 特定の key を削除する関数
const delteObjectKey = (object, deleteTargetKey) => {
return Object.keys(object).reduce((obj, key) => {
if (key !== deleteTargetKey) {
return { ...obj, [key]: person[key] }
}
return obj
}, {})
}
// person オブジェクトから age という key を削除する
const newPerson = delteObjectKey(person, 'age')
console.log(newPerson)
try {
// deepFreeze させているので、
// プロパティを削除するとエラーが出る
delete person.age
} catch (err) {
console.error(err.message)
}
Functional Programming を意識する
map, reduce 等をうまく使う。
詳しくは手前味噌ですみませんが、次の記事を参照してください。
JavaScript おじさんが教える ES2015+ と関数型プログラミング 1
まとめ
以下の三つを守って、可読性が高く、変更に強い JavaScript を書く。
- 全て const を使う(くらいの気持ちで)
- Immutable にする(Object の property, Array の要素を変更しない)
- Functional Programming を意識する