JavaScript
es6

JavaScript中級TIPS

More than 1 year has passed since last update.

文字列リテラル

HTMLを含む文字列を生成する際に便利なため、囲む時はシングルクォート'hoge'がよい

セミコロン

末尾にセミコロンをつけなくても解釈してくれるが、バグを生む可能性があるのでセミコロンはつけるように習慣化する

ES6のclass記法のメソッド末尾にはセミコロン不要

同値比較

基本的に===をつかう。==だと寛容過ぎる解釈のため、バグを生むことがある。

短絡評価

hogeFuncの引数にtrue相当の値が入ってきた場合、
||の右側は読まれない。

hogeFuncの引数にfalse相当の値が入ってきた場合、
false, null, undefined, NaN, "", 0
||の右側を読みにいく。

function hogeFunc(e){
    e || console.log('piyo');
}
hogeFunc(1); // 何も出力されない。もし短絡評価がなければ右側も評価されるのでpiyoが出力される
hogeFunc(); // piyoが出力される

こういう使い方も

function hogeFunc(e){
    var hoge = e || 1;
    console.log(hoge);
}
hogeFunc(5); // 5
hogeFunc(); // 1

for文

for(let i = 0, j = 0; i < 3; i++, j+=2){ // カンマで複数追加もできる
  console.log(i,j);
}

for...inはインデックス番号やキー名を取り出すだけなので、連想配列やオブジェクトを走査するときだけに使う。不便。

[追記] 20160808
「for...in列挙遅すぎ問題」「prototype汚染列挙問題」等が存在しますので、現代的なJavaScriptにおいてはそもそも for...in 自体を使わない方が安全です。

一方、ES6のfor...ofは値を返してくれるので便利。

Array.prototype.keys()Array.prototype.entries()も使えばもっと便利

let arr1 = ['a','b'];
let arr2 = ['あ','い','う'];
// ...iterable
// イテラブルなオブジェクトの値を順次取り出す
let margeArr = [...arr1, ...arr2]; // 配列の結合もできる

for(let val of margeArr){
  console.log(val);
    // "a"
    // "b"
    // "あ"
    // "い"
    // "う"
}
for(let val of margeArr.keys()){
  console.log(val);
    // 0
    // 1
    // 2
    // 3
    // 4
}
for(let [i, val] of margeArr.entries()){
  console.log(i, val);
    // 0 "a"
    // 1 "b"
    // 2 "あ"
    // 3 "い"
    // 4 "う"
}

配列操作の詳細はこちら
http://qiita.com/mo4_9/items/2968fea172c028d58aec

具体例 引数の渡し方
プリミティブ boolean, number, string, symbol(ES6), null, undefined 値渡し
その他 object 参照渡し

プリミティブ型

  • boolean, number, string, symbol(ES6)
    オブジェクトとして振舞おうとした際に、バックグラウンドでそれぞれの型に応じたラッパーオブジェクトが生成される。
    (ちなみにES6からプリミティブ型の明示的なラッパーオブジェクトの作成はサポートされなくなった為、Symbolはnewできない)

  • null, undefined
    ラッパーオブジェクトなし。常にプリミティブ型。

参考
javascript ラッパーオブジェクト
ES6で追加された新しいプリミティブ値Symbolのメモ

null と undefined の違い

nullはエンジニアが意図的にセットしないと出会すことはない。
undefinedはエンジニアのミスで発生する。

初心者はざっくりと上記の認識でok
あとは以下のような地雷を踏んだとき、その都度覚えていけばいい

// #hogeがDOMに存在しない状態で
console.log( document.getElementById('hoge') ); // null
console.log( 'hoge'.match(/a/) ); // null

null:定義済み(存在している)だが、値や型がない
undefined:未定義(存在していない)

参考
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/null

型変換

-(マイナス)は数値演算子にしかないので、Stringの'1'- 0すると'1'がNumberに暗黙で型変換(キャスト)される。+(プラス)はStringの連結にも使うのでNumberへの型変換はおこなわれない。

暗黙的型変換
'1' - 0 // 1 (Number)
'1' + 0 // '10' (String)

しかし上記はパッと見わかりにくいので、使わないほうがいい。
代替案としてparseInt()Number()
さらにparseInt()のほうが柔軟に処理してくれるので便利と言える

parseInt()とNumber()
parseInt('1') // 1
parseInt('1px') // 1
Number('1') // 1
Number('1px') // NaN -> Not-A-Numberの略でnumber型

参考
型変換のいろいろ

JSON

ごちゃっとしたデータはJSONにまとめる

変換ツール
http://shancarter.github.io/mr-data-converter/

整形ツール
https://chrome.google.com/webstore/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh

関数

JavaScriptにおける関数は第一級オブジェクトである。
型は「 [[Call]] を持つ Object 型 」であり、関数型は存在しない。

参考
まさに忍者...JavaScriptの関数は第一級オブジェクト
12.5.6 The typeof Operator – ECMA-262 6th Edition

即時関数

!を先頭につけるとシンプルになる。小ネタ。

!function hoge() {
  console.log('hoge');
}();

ES6からはブロックスコープのマスキングが不要だったりするので使用頻度は減りそうだが、以下のようなケースでは使用する必要あり。

・名前付き関数式で再帰呼び出し
・Function.prototype.call() で this 値を変更

StrictModeでグローバルオブジェクトを渡す
'use strict';
(function () {
  console.log(this);
}.call(this));

参考
Function.prototype.call()
JavaScript, 即時関数でthisを指定して引数も受け取る
ES2015(ES6)新構文:アロー関数(Arrow function)
ES2015(ES6)の即時関数は短く書けるしletならそもそも不要

Class

クラス名 -> 名詞
メソッド名 -> 動詞

なるべく細かく外部ファイルに切り分ける
1ファイル100行以内くらいが理想

new演算子

オブジェクトのインスタンスを返却しなさい!とコンストラクタに命令する演算子。
自動的にreturnしているということ。

this

よくあるハックself=this;
class class1 {
  func1(){
    // ここでのthis=class1オブジェクト
    const self = this;

    img.addEventListener('load', function(){
      // ここでのthis=img
    }, false);
  }
}

argumentsオブジェクト

関数呼び出しの際に引数のチェックがないのでargumentsオブジェクトで管理する。
ES6だと可変長引数を容易に配列に格納できる。

function f(x, ...aiu) {
  console.log(x, aiu); // 1 ["a", "i", "u"]

  // 引数の値を取得
  for(let i = 0; i < arguments.length; i++){
    console.log(arguments[i]);
  }

  // エラーハンドリング
  if(arguments.length != 2){
    throw new Error('引数の数が不正です');
  }

  // 可変長引数の値を取得
  for(let arg of aiu){
    console.log(arg);
  }

}

f(1, 'a', 'i', 'u');

引数が多い場合は、引数に名前をつけるとわかりやすい

function person(opts = {}){ // 初期値の設定
  const name = opts.name;
  const age = opts.age;

  console.log(name,age);
}

person ({
  name:'bob',
  age:30
});

※ES6前提なら可変長引数だけで十分。argumentsは不要。

bind

thisを束縛する

function sum (val1,val2){
  console.log(this.val + val1 + val2);
}
let obj1 = {val: 1};
let obj2 = {val: 2};

let obj1Sum = sum.bind(obj1); // thisだけを指定
let obj2Sum = sum.bind(obj2,2,2); // thisと引数を指定

obj1Sum(1,1); // 3
obj2Sum(); // 6

thisをnullにして、引数のみを束縛する

function sum(x,y,z){
  console.log(x+y+z);
}

let sumA = sum.bind(null,1);
sumA(2,3); // 6

get / set

functionの部分をget/setにする

let human = (() => {
  let _name;
  return { // クロージャ
    get name(){
      return `名前は${_name}です`;
    },
    set name(val){
      _name = val;
    }  
  }
})(); // 即時実行

human.name = 'steve';
human._name = 'jobs';
console.log(human.name);
console.log(human._name);

Ajax

Ajax通信

http://qiita.com/mo4_9/items/22eaf3bf469b8c272df7

Deferred

http://qiita.com/mo4_9/items/67763587e6f0f7306ca4

イベント

イベントの伝播

http://qiita.com/mo4_9/items/f05cb7b0518b4a7dbd5d

カスタムイベント

http://qiita.com/mo4_9/items/2ac77bdc7399600bc2d4

クロージャ

http://qiita.com/mo4_9/items/baa7fc28aafb04517d57

参考
ES6 チートシート
JavaScriptの理解を深めた人がさらにもう一歩先に進むための本