Skip to content

Instantly share code, notes, and snippets.

@likr
Last active November 2, 2016 02:50
Show Gist options
  • Save likr/c4b9dda04562b6491674f3994d27111e to your computer and use it in GitHub Desktop.
Save likr/c4b9dda04562b6491674f3994d27111e to your computer and use it in GitHub Desktop.
20160924KFUG

JavaScript コーディング TIPS

自己紹介

おのうえ(@_likr)です。

概要

モダンJavaScriptの便利な書き方や、Linterに怒られないコードの書き方などを紹介します。

Linter

ESLint

http://eslint.org/

$ npm i -g eslint
$ eslint --init
$ eslint hoge.js

standard

http://standardjs.com/

  • 細かいことを考えたくない人向け
  • セミコロンなし派?
    • なくていいものはなくていいんじゃない
$ npm i -g standard
$ standard hoge.js

for vimmer

https://github.com/scrooloose/syntastic

良い実装とは?

要件に対して過不足がないこと。

ES2015

各ブラウザ最新バージョンなら大体動く。 http://kangax.github.io/compat-table/es6/ Node 6でも動く。 ちょっと古いバージョンはbabeって。 https://babeljs.io/

var, let, const

varはいらない子。 変更する変数はlet、変更しない変数はconst。

let a = 1
a = 2

const b = 'x'
// ×
// b = 'y'

Arrow functions

深い理由がなければ、もう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})

Template strings

const x = 1

const s1 = 'x = ' + x + '!'

const s2 = `x = ${x}!`

文字列内で改行できて便利。

const template = `
<div>
  <div>
    <div>
    </div>
  </div>
</div>
`

for of

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なら使える。

Destructuring

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

Set

集合に要素が含まれているか高速に判定可能。 重複要素を取り除いたりも。

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)
} 

Map

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]))

Object

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

ループを書く前に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

自分で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]) => {
    // ...
  })

Rest & Spread

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 field

どうしても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()

ArrayBuffer & TypedArray

速くしたい人とかバイナリ扱う人向け。

window.fetch('/data')
  .then((response) => response.arrayBuffer())
  .then((buffer) => {
    const data = new Float32Array(buffer)
    // ...
  })

ES2016

Array.prototype.includes

各ブラウザ最新版だと使える。 もう2016年なので。

const a = [1, 2, 3, 4, 5]

// ×
if (a.indexOf(3) !== -1) {
}

// ◯
if (a.includes(3)) {
}

exponentiation operator

Chrome、Edgeで使える。

const x = 2 ** 3

ES2017

babel的にはlatest。

Object.values, Object.entries

for (const value of Object.values(obj)) {
}

for (const [key, value] of Object.entries(obj)) {
}

Async Functions

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)
}

ECMAScript Proposals

https://github.com/tc39/proposals

SIMD

早くしたい人向け。

Observable

RxJS 5はこれ準拠らしい。

const observable = new Observable((observer) => {
  const id = setInterval(() => {
    observer.next('next')
  }, 1000)
  return () => {
    clearInterval(id)
  }
})

observable.subscribe((val) => {
  console.log(val)
})

function bind

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を使おう。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment