おのうえ(@_likr)です。
モダンJavaScriptの便利な書き方や、Linterに怒られないコードの書き方などを紹介します。
$ npm i -g eslint
$ eslint --init
$ eslint hoge.js
- 細かいことを考えたくない人向け
- セミコロンなし派?
- なくていいものはなくていいんじゃない
$ npm i -g standard
$ standard hoge.js
https://github.com/scrooloose/syntastic
要件に対して過不足がないこと。
各ブラウザ最新バージョンなら大体動く。 http://kangax.github.io/compat-table/es6/ Node 6でも動く。 ちょっと古いバージョンはbabeって。 https://babeljs.io/
varはいらない子。 変更する変数はlet、変更しない変数はconst。
let a = 1
a = 2
const b = 'x'
// ×
// b = 'y'
深い理由がなければ、もうfunctionを使う必要はない。
// ×
function f1 () {
}
// △
const f2 = function () {
}
// ◯
const f3 = () => {
}
// × space-before-function-paren
function f1() {
}
let f2 = function() {
}
// △ arrow-parens
const f1 = x => 2 * x
// ◯
const f2 = (x) => 2 * x
const f3 = (x) => {
return 2 * x
}
// △ comma-spacing, arrow-spacing, space-infix-ops
const f1 = (x,y)=>x+y
// ◯
const f2 = (x, y) => x + y
オブジェクトを返したいとき。 みかかねさんが好きなやつ。
const f1 = () => ({})
const f2 = (arg) => ({val: arg})
const x = 1
const s1 = 'x = ' + x + '!'
const s2 = `x = ${x}!`
文字列内で改行できて便利。
const template = `
<div>
<div>
<div>
</div>
</div>
</div>
`
const a = [1, 2, 3, 4, 5]
// ×
for (let i = 0; i < a.length; ++i) {
const ai = a[i]
console.log(ai)
}
// ◯
for (const ai of a) {
console.log(ai)
}
Array.prototype.forEachと比べると、ループ途中で関数から抜けたい時に便利。
const f = (a) => {
for (const x of a) {
if (x === 0) {
return true
}
}
return false
}
Arrayじゃなくても、Iteratorなら使える。
const array = [1, 2, 3]
const obj = {a: 1, b: 2, c: 3}
const [a1, a2] = array
const {a, c} = obj
const f1 = ([_, val]) => val
const f2 = ({val}) => val
集合に要素が含まれているか高速に判定可能。 重複要素を取り除いたりも。
const a = [1, 2, 3, 1, 2, 1, 4]
const s = new Set(a)
s.add(5)
s.delete(4)
s.has(1)
for (const x of s) {
console.log(x)
}
String(とNumber)以外もキーになれる。 Map的な使い方をするならObjectはやめてMapへ。
const obj = {}
const m = new Map()
m.set('key', 'value')
m.set(1, 'one')
m.set(obj, 'obj')
console.log(m.get(obj))
const a = [1, 2, 3, 4, 5]
const aValueToIndexMap = new Map(a.map((x, i) => [i, x]))
const a = 1
const b = 2
const obj = {a, b}
Object.assign(obj, {
c: 3,
d: 4
})
for (const key of Object.keys(obj)) {
}
ループを書く前にArrayのメソッドでできないか考えよう。
const obj = {a: 1, b: 2, c: 3, d: 4}
const oddValues = Array.from(Object.keys(obj))
.map((key) => obj[key])
.filter((value) => value % 2 == 0)
oddValues.every((x) => x % 2 === 0)
oddValues.some((x) => x % 2 === 1)
oddValues.join(',')
oddValues.find((x) => x > 3)
oddValues.findIndex((x) => x > 3)
自分でPromiseを作ったことはありますか?
const f = () => new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, 1000)
})
const f = () => Promise.resolve(1)
f().then((result) => {
console.log(result)
})
const resource1 = window.fetch('/resouce1')
.then((response) => response.json())
const resource2 = window.fetch('/resource2')
.then((response) => response.json())
Promise.all([resource1, resource2])
.then(([data1, data2]) => {
// ...
})
const sum = (...values) => values.reduce((a, b) => a + b)
sum(1, 2, 3)
const a = [1, 2, 3, 4]
sum(...a)
// ×
Math.min.apply(null, a)
// ◯
Math.min(...a)
どうしてもprivateを大事にしたい人へ。
const Hoge = (() => {
const privates = new WeakMap()
return class {
constructor (arg) {
privates.set(this, arg)
}
f () {
return privates.get(this)
}
}
})()
const obj = new Hoge(3)
obj.f()
速くしたい人とかバイナリ扱う人向け。
window.fetch('/data')
.then((response) => response.arrayBuffer())
.then((buffer) => {
const data = new Float32Array(buffer)
// ...
})
各ブラウザ最新版だと使える。 もう2016年なので。
const a = [1, 2, 3, 4, 5]
// ×
if (a.indexOf(3) !== -1) {
}
// ◯
if (a.includes(3)) {
}
Chrome、Edgeで使える。
const x = 2 ** 3
babel的にはlatest。
for (const value of Object.values(obj)) {
}
for (const [key, value] of Object.entries(obj)) {
}
const f = async () => {
const res1 = await fetch('/res1').then((response) => response.json())
const res2 = await fetch(`/res2/${res1.id}`).then((response) => response.json())
console.log(res2)
}
https://github.com/tc39/proposals
早くしたい人向け。
RxJS 5はこれ準拠らしい。
const observable = new Observable((observer) => {
const id = setInterval(() => {
observer.next('next')
}, 1000)
return () => {
clearInterval(id)
}
})
observable.subscribe((val) => {
console.log(val)
})
class Hoge extends React.Component {
render () {
return <div>
<button onClick={this.handleClick.bind(this)} />
<button onClick={::this.handleClick} />
</div>
}
handleClick () {
}
}
import { Observable } from 'rxjs/Observable'
import { of } from 'rxjs/observable/of'
import { map } from 'rxjs/operator/map'
Observable::of(1, 2, 3)::map((x) => x + '!!!')
- 新しい便利な言語機能は使おう。
- ES2015は複数の言語機能を組み合わせると効果を増す感じ。
- コーディングスタイルには一貫性を持とう。
- コーディングスタイルを保つためにLinterを使おう。