#nakano_lt で 「5分でつくる jQuery 2015」を話した話

http://3846masa.blog.jp/archives/1043609084.html とだいたい同じ

# \#nakano_lt とは
中野区にある明治大学中野キャンパスで不定期に行われているLTイベント．

http://nakano-lt.github.io/004/

今回の開催が4回目で初めての早朝開催だった．

この話は，僕がLTの準備をする前に寝てしまって，丸腰でLT登壇へ臨んだときの話．

# 5分で作るjQuery 2015
ほぼ即席で話した（もといデモした）が， **5分は短い**．

## jQueryとは
- JavaScriptのライブラリ
- DOMセレクタ，Ajax，アニメーション処理など
  - Qiita読んでいる人は知っていると思う

```js
// サイト内のリンク先をすべて抽出
$('a').map(function(){ return $(this).attr('href'); }).get();
```

## 5分で作るjQueryで搭載する機能
- DOMセレクタ

```js
// サイト内のaタグをすべて抽出
$('a');
```

- イベントリスナー

```js
// pタグをクリックしたらalertを出す
$('p').on('click', function() { alert('Clicked.'); });
```

- Ajax

```js
// サイトトップを取ってくる
$.ajax({
  url: '/',
  method: 'GET'
}).done(function(body) {
  console.log(body);
});
```

## DOMセレクタ
- ChromeDevToolsのコンソールにはデバッグ用の関数がある
  - firefoxにもあったし，IEにもありそう

### デバッグコンソールにある$と$$
- ``$(selector[, parentNode])``は最初にヒットするDOMを返す

```js
// 最初にヒットするDOMを返す
delete $; // delete jQuery
$('a') === document.querySelector('a'); // true
```

- ``$$(selector[, parentNode])``はヒットするDOMのリストを返す

```js
var dollars = $$('a');
var normal = document.querySelectorAll('a');
dollars.length === normal.length; // true
```

### DOMセレクタの実装
- ``querySelector()``があるのでそれにつなげてやればいい

```js
var $ = function(sel, node) {
  return (node || document).querySelector(sel);
};
var $$ = function(sel, node) {
  return (node || document).querySelectorAll(sel);
};
```

> 注）デバッグコンソールに貼り付けて試すとき，1度変数宣言してからでないと代入されなかった．原因求む．

- 引数1つだと``node``は``undefined``なので``document.querySelector``が呼ばれる

### NodeListの問題
- ``querySelectorAll()``で取れるDOMリストは **配列ではない**
  - NodeListが返ってくる
  - デバッグ用``$$()``は配列で返る

```js
// 前述のコードを読み込んだあと
$$('a').forEach; // undefined
```

- ``Array.from()``をつかうとarray-likeなオブジェクトを配列にできる
  - [MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
  - ES2015から使えるようになった
  - それまでは``Array.prototype.slice.call(arrLike);``とかやってた
     - ``Array.from`` notEquals ``Array.prototype.slice.call``

```js
var $$ = function(sel, node) {
  var ArrayFromNL = Array.from || function(nodes) {
    return Array.prototype.slice.call(nodes);
  };
  var nodeList = (node || document).querySelectorAll(sel);
  return ArrayFromNL(nodeList);
};
```

## イベントリスナー
- ``addEventListener``を``on``にしてやればいい
  - DOMだけならば``HTMLElement``に対して行う
  - すべてならば``EventTarget``に対して行う
      - ``XMLHttpRequest``や``document``など

```js
EventTarget.prototype.on = EventTarget.prototype.addEventListener;
```

- ``off``の実装は手間なので省略
  - ``removeEventListener``は削除したい関数が引数に必要
     - つまり無名関数は削除できない
  - そう考えるとjQuery便利
     - jQueryは無名関数を保管しているので削除できる

### attachEvent
- 古いIEでは``attachEvent``を使う
  - [MDN](https://developer.mozilla.org/ja/docs/Web/API/EventTarget/addEventListener#Compatibility)
  - ぼくはIE使わないから(ry
- jQueryはそこもしっかりやってくれる

## Ajax
- ``fetch``関数というものがある
  - Chrome42, firefox39 から搭載
     - [MDN - 対応状況](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API#Browser_compatibility)
     - [Can I use](http://caniuse.com/#feat=fetch)
  - Githubから[polyfill](https://github.com/github/fetch)が出ている
     - 大体のブラウザで動く
  - Promiseをつかっている
     - [Can I use](http://caniuse.com/#feat=promises)
     - [JavaScript Promiseの本](http://azu.github.io/promises-book/)

```js
fetch('/', {
  method: 'GET'
})
.then((res) => {
  if (parseInt(res.status/100) !== 2) {
    throw new Error(`${res.status} ${res.statusText}`);
  }
  return res.text();
})
.then((body) => {
  console.log(body);
})
.catch((err) => {
  console.error(err.stack);
});
```

- ``$.ajax``は2種類書き方がある
  - [Reference](http://api.jquery.com/jquery.ajax/)

```js
$.ajax('/', {
  method: 'GET'
})
.done((body) => {
  console.log(body);
})
.fail((err) => {
  console.error(err);
});
```
```js
$.ajax({
  url: '/',
  method: 'GET'
})
.done((body) => {
  console.log(body);
})
.fail((err) => {
  console.error(err);
});
```

- どこまで似せるか
  - 5分しかないし最初のほうだけにする
  - ``fetch()``に似ているから楽

```js
$.ajax = function() {
  return fetch.apply(window, arguments)
    .then(function(res) {
      if (parseInt(res.status/100) !== 2) {
        throw new Error(res.status + ' ' + res.statusText);
      }
      return res.text();
    });
};
```
```js
$.ajax('/', {
  method: 'GET'
})
.then((body) => {
  console.log(body);
})
.catch((err) => {
  console.error(err.stack);
});
```

- 正直``fetch()``をそのまま使うほうがよい

## まとめ
```js
var $ = function(sel, node) {
  return (node || document).querySelector(sel);
};
var $$ = function(sel, node) {
  var ArrayFromNL = Array.from || function(nodes) {
    return Array.prototype.slice.call(nodes);
  };
  var nodeList = (node || document).querySelectorAll(sel);
  return ArrayFromNL(nodeList);
};

EventTarget.prototype.on = EventTarget.prototype.addEventListener;

$.ajax = function() {
  return fetch.apply(window, arguments)
    .then(function(res) {
      if (parseInt(res.status/100) !== 2) {
        throw new Error(res.status + ' ' + res.statusText);
      }
      return res.text();
    });
};
```

- コード短いけど，5分で解説は無理でした
  - ``$()``のコードだけでも書けると便利だと思う
- 素直にjQuery使ったほうがいい気がする
  - 勉強も兼ねてこういうことするのはよいと思う
- 最近PCの``q``キーが効かない
  - つらい