たまにはjQueryに頼るのをやめてみる

#はじめに

ありとあらゆる所で使用されている超有名なJavaScriptライブラリといえば jQuery ですが、ちょっとした処理を行いたいがために使っているようであれば無駄な気もします。
最近のJavaScriptはjQueryなしでも割といろんな処理を行うことができます。

というのも、jQueryの動作を模倣してみようとゼロから書いた拙作のライブラリ queries.js を通してどのような処理を行っているのか理解が深まったからです。
宣伝になってしまいますが、queries.js へのリンクを貼っておきます。
[jQueryライクなJavaScriptライブラリ queries.js](http://memo.sdn-project.net/post/142395979444/queriesjs)

ちなみに、処理に関しては Internet Explorer 11 未満は考慮していません。

ここに書かれているコードのほとんどは**意図的に**関数化していません。これらのコードを元に自由に組んで自分で使いやすい関数にしていく方がいいと思うからです。

---

2017/04/07 追記： `.index()`, `.has()` を追加しました！
2017/03/28 追記： `$.ajax()` を追加しました！
2017/03/21 追記： `$.inArray()`, `$.proxy()`, `.siblings()`, `.nextAll()`, `prevAll()` を追加しました！
2017/03/17 追記： `.closest()`, `.width()` 等を追加しました！
2017/03/16 追記：他のメソッドも追加しました！

#便利メソッド系

`$.each()` や `$.grep()` といったメソッドの代替となる記述です。
よく使いそうなものだけ取り上げています。

##$.each()

`$.each()` は、配列やオブジェクトを簡単にループ処理できるメソッドです。

以下のような配列とオブジェクトがあったとします。

```js:ループさせる配列とオブジェクト
// 配列
var decoRations = ['諸星きらり', '城ヶ崎莉嘉', '赤城みりあ'];

// 配列っぽいオブジェクト
var candyIsland = {0: '双葉杏', 1: '三村かな子', 2: '緒方智絵里', length: 3};

// オブジェクト
var kbyd = {kawaii: '輿水幸子', yakyu: '姫川友紀', dosue: '小早川紗枝'};
```

これをループさせます。

```js:jQueryを使った例
/* 配列 */
$.each(decoRations, function (i, value) {
  console.log(i + ': ' + value);
});
// "0: 諸星きらり"
// "1: 城ヶ崎莉嘉"
// "2: 赤城みりあ"

/* 配列っぽいオブジェクト */
$.each(candyIsland, function (i, value) {
  console.log(i + ': ' + value);
});
// "0: 双葉杏"
// "1: 三村かな子"
// "2: 緒方智絵里"

/* オブジェクト */
$.each(kbyd, function (key, value) {
  console.log(key + ': ' + value);
});
// "kawaii: 輿水幸子"
// "yakyu: 姫川友紀"
// "dosue: 小早川紗枝"
```

```js:jQueryを使わない例
/* 配列 */
// Array.prototype.forEach
decoRations.forEach(function (value, i) {
  console.log(i + ': ' + value);
});
// "0: 諸星きらり"
// "1: 城ヶ崎莉嘉"
// "2: 赤城みりあ"

/* 配列っぽいオブジェクト */
var forEach = Array.prototype.forEach;
forEach.call(candyIsland, function (value, i) {
  console.log(i + ': ' + value);
});
// "0: 双葉杏"
// "1: 三村かな子"
// "2: 緒方智絵里"

/* オブジェクト */
// for...in 文
for (var key in kbyd) {
  console.log(key + ': ' + kbyd[key]);
}
// "kawaii: 輿水幸子"
// "yakyu: 姫川友紀"
// "dosue: 小早川紗枝"

// Object.keys() を使った方法
Object.keys(kbyd).forEach(function (key) {
  console.log(key + ': ' + kbyd[key]);
});
// "kawaii: 輿水幸子"
// "yakyu: 姫川友紀"
// "dosue: 小早川紗枝"
```

配列の場合は、`Array.prototype.forEach` を使った方法、配列っぽいオブジェクトは `Array.prototype.forEach.call()` として配列として振る舞うようにする方法、オブジェクトの場合は `for...in` 文や `Object.keys` を利用した方法です。
`$.each()` との違いは、コールバック関数の引数の順番や直接オブジェクトを使えない事、`return false` でもループが止まらないことでしょうか。
`Array.prototype.forEach` は関数を利用した方法なので、`break` や `continue` は使えませんが、`continue` に関しては `return` で代用できます。このメソッドでは、返り値を指定しても意味ありません。

ループを止める処理を行いたい場合、本来の使い方ではなくなってしまいますが、`Array.prototype.some` で似たような事を行えます。

```js:ループを途中で止める
var kawaii142s = ['輿水幸子', '白坂小梅', 'あの子', '星輝子'];

/* jQuery */
$.each(kawaii142s, function (i, value) {
  console.log(value);

  if (value === 'あの子') {
    console.log('フギャー！？');
    return false;
  }
});
// "輿水幸子"
// "白坂小梅"
// "あの子"
// "フギャー！？"

/* Array.prototype.some */
kawaii142s.some(function (value) {
  console.log(value);

  if (value === 'あの子') {
    console.log('フギャー！？');

    // return true; なので注意
    return true;
  }
});
// "輿水幸子"
// "白坂小梅"
// "あの子"
// "フギャー！？"
```

うーん、これはちょっとおすすめできないですね……

ちなみに、ECMAScript 2015 (ES6) では `for...of` 文が使えるので、`break` や `continue` も使えます。

```js:for...of
for (let value of kawaii142s) {
  console.log(value);

  if (value === 'あの子') {
    console.log('フギャー！？');
    break;
  }
}
// "輿水幸子"
// "白坂小梅"
// "あの子"
// "フギャー！？"
```

##$.extend()

オブジェクトのマージを行うメソッドです。

以下のような二つのオブジェクトがあるとします。

```js:マージするオブジェクト
var
  nickname01 = {
    uzuki: 'しまむー',
    rin:   'しぶりん',
    ranko: 'らんらん',
    riina: 'りーな',
    miku:  'みくにゃん',
  },
  nickname02 = {
    sachiko: 'さっちー',
    kirari:  'きらりん',
    riina:   'だりー',
    mika:    'みかねえ',
    rika:    'りかちー',
  };
```

これらをマージしてみます。

```js:jQueryを使った例
$.extend(nickname01, nickname02);
```

```js:jQueryを使わない例
// for...in 文で行う場合
for (var key in nickname02) {
  nickname01[key] = nickname02[key];
}

// Object.keys() を利用する場合
Object.keys(nickname02).forEach(function (key) {
  nickname01[key] = nickname02[key];
});
```

`nickname01` は以下のようなオブジェクトになります

```js:結果
nickname01 = {
  kirari:  'きらりん',
  mika:    'みかねえ',
  miku:    'みくにゃん',
  ranko:   'らんらん',
  riina:   'だりー',
  rika:    'りかちー',
  rin:     'しぶりん',
  sachiko: 'さっちー',
  uzuki:   'しまむー',
};
```

ちなみに、ECMAScript 2015 では `Object.assign()` が `$.extend()` とほぼ同じ処理をしてくれます。

```js:Object.assign()を使用した例
let
  nickname01 = {kirari: 'きらりん', mika: 'みかねえ', miku: 'みくにゃん'},
  nickname02 = {ranko: 'らんらん', riina: 'だりー', rika: 'りかちー'},
  nickname03 = {rin: 'しぶりん', sachiko: 'さっちー', uzuki: 'しまむー'};

// $.extend(nickname01, nickname02, nickname03); と同じ結果
Object.assign(nickname01, nickname02, nickname03);
```

`$.extend(true, obj1, obj2)` とすることでディープマージを行えますが、ここでは簡単な方法のみ扱います。

##$.grep()

配列をフィルタリングするためのメソッドです。

```js:jQueryを使った例
var kawaii142s = ['輿水幸子', '白坂小梅', 'あの子', '星輝子'];

kawaii142s = $.grep(kawaii142s, function (value) {
  return value !== 'あの子';
});

console.log(kawaii142s);
// ["輿水幸子", "白坂小梅", "星輝子"]
```

`Array.prototype.filter` で同じことができます。

```js:jQueryを使わない例
var kawaii142s = ['輿水幸子', '白坂小梅', 'あの子', '星輝子'];

kawaii142s = kawaii142s.filter(function (value) {
  return value !== 'あの子';
});

console.log(kawaii142s);
// ["輿水幸子", "白坂小梅", "星輝子"]
```

##$.map()

配列の値を関数を通して新しい配列として出力するメソッドです。

```js:jQueryを使った例
var result = $.map([0, 1, 2, 3, 4], function (value) {
  return value * 2;
});

console.log(result);
// [0, 2, 4, 6, 8]
```

`Array.prototype.map` で同じことができます。

```js:jQueryを使わない例
var result = [0, 1, 2, 3, 4].map(function (value) {
  return value * 2;
});

console.log(result);
// [0, 2, 4, 6, 8]
```

##$.merge()

配列をマージする時に使うメソッドです。

```js:jQueryを使った例
var
  asterisk = ['前川みく', '多田李衣菜'],
  natsunana = ['木村夏樹', '安部菜々'];

$.merge(asterisk, natsunana);

console.log(asterisk);
// ["前川みく", "多田李衣菜", "木村夏樹", "安部菜々"]
```

これも簡単に書き直せます。（変数は上と同じ）

```js:jQueryを使わない例
// Array.prototype.push.apply
asterisk.push.apply(asterisk, natsunana);

console.log(asterisk);
// ["前川みく", "多田李衣菜", "木村夏樹", "安部菜々"]
```

ECMAScript 2015 なら更にこのように書けます。

```js:jQueryを使わない例（ES2015）
// Array.prototype.push
asterisk.push(...natsunana);

console.log(asterisk);
// ["前川みく", "多田李衣菜", "木村夏樹", "安部菜々"]
```

##$.contains()

要素の子要素に指定した要素が含まれているかの真偽値を返すメソッドです。

```js:jQueryを使った例
// document.documentElement の子要素に document.body は含まれている
$.contains(document.documentElement, document.body);  // true

// document.body の子要素に document.documentElement は含まれていない
$.contains(document.body, document.documentElement);  // false

// 自分自身は含まれない扱いになる
$.contains(document.body, document.body);  // false
```

`Node.contains()` を利用する事で代用できます。

```js:jQueryを使わない例
// document.documentElement の子要素に document.body は含まれている
document.documentElement.contains(document.body);  // true

// document.body の子要素に document.documentElement は含まれていない
document.body.contains(document.documentElement);  // false

// 自分自身も含む扱いになる
document.body.contains(document.body);  // true

// 自分自身は含まないようにする場合はこのような関数を用意する
function contains(parent, child) {
  return parent !== child && parent.contains(child);
}
contains(document.body, document.body);  // false
```

##$.inArray()

指定した値が配列に存在する場合、最初に見つけたもののインデックスを返します。

```js:jQueryを使った例
var lipps = ['速水奏', '城ヶ崎美嘉', '塩見周子', '宮本フレデリカ', '一ノ瀬志希'];

$.inArray('城ヶ崎美嘉', lipps);  // 1
$.inArray('城ヶ崎莉嘉', lipps);  // -1
```

`Array.prototype.indexOf` を使用します。

```js:jQueryを使わない例
var lipps = ['速水奏', '城ヶ崎美嘉', '塩見周子', '宮本フレデリカ', '一ノ瀬志希'];

lipps.indexOf('城ヶ崎美嘉');  // 1
lipps.indexOf('城ヶ崎莉嘉');  // -1
```

##$.isArray()

配列かどうかの真偽値を返すメソッドです。

```js:jQueryを使った例
$.isArray([]);  // true
$.isArray({});  // false
```

```js:jQueryを使わない例
Array.isArray([]);  // true
Array.isArray({});  // false
```

##$.type()

指定したオブジェクトの型（クラス）を判定します。

```js:jQueryを使った例
$.type([]);              // "array"
$.type({});              // "object"
$.type('');              // "string"
$.type(123);             // "number"
$.type(function () {});  // "function"
```

`Object.prototype.toString.call()` で同じことができます。

```js:jQueryを使わない例
var toString = Object.prototype.toString;
function typeOf(obj) {
  return toString.call(obj).slice(8, -1).toLowerCase();
}

typeOf([]);              // "array"
typeOf({});              // "object"
typeOf('');              // "string"
typeOf(123);             // "number"
typeOf(function () {});  // "function"
```

`$.isPlainObject()`, `$.isFunction()` といった判定系のメソッドはこの判定のショートハンドなので、こちらで事足ります。

##$.isEmptyObject()

指定したオブジェクトが空のオブジェクトかどうかの真偽値を返すメソッドです。

```js:jQueryを使った例
$.isEmptyObject({});                            // true
$.isEmptyObject({yaminoma: '闇に飲まれよ！'});  // false
```

```js:jQueryを使わない例
function isEmptyObject(obj) {
  return Object.prototype.toString.call(obj) === '[object Object]' &&
    Object.keys(obj).length === 0;
}

isEmptyObject({});                            // true
isEmptyObject({yaminoma: '闇に飲まれよ！'});  // false
```

空のオブジェクトで `Object.keys()` を使用すると空の配列になるのを利用した方法です。

##$.isWindow()

`window` オブジェクトかどうかの真偽値を返すメソッドです。

```js:jQueryを使った例
$.isWindow(window);    // true
$.isWindow(document);  // false
```

```js:jQueryを使わない例
function isWindow(obj) {
  return !!obj && obj === obj.window;
}

isWindow(window);    // true
isWindow(document);  // false
```

`window === window.window` を利用した方法です。

##$.isNumeric()

有効な数値かどうかの真偽値を返すメソッドです。

```js:jQueryを使った例
$.isNumeric(123);       // true
$.isNumeric('123');     // true
$.isNumeric('-123');    // true
$.isNumeric(0x7b);      // true
$.isNumeric('0x7b');    // true
$.isNumeric(1e10);      // true
$.isNumeric('1e10');    // true

$.isNumeric('');        // false
$.isNumeric(null);      // false
$.isNumeric(NaN);       // false
$.isNumeric(Infinity);  // false
```

```js:jQueryを使わない例
var toString = Object.prototype.toString;
function typeOf(obj) {
  return toString.call(obj).slice(8, -1).toLowerCase();
}

function isNumeric(obj) {
  var type = typeOf(obj);
  return (type === 'number' || type === 'string') && !isNaN(obj - parseFloat(obj));
}

isNumeric(123);       // true
isNumeric('123');     // true
isNumeric('-123');    // true
isNumeric(0x7b);      // true
isNumeric('0x7b');    // true
isNumeric(1e10);      // true
isNumeric('1e10');    // true

isNumeric('');        // false
isNumeric(null);      // false
isNumeric(NaN);       // false
isNumeric(Infinity);  // false
```

##$.parseHTML()

HTML文字列をノードリストに変換します。

```js:jQueryを使った例
// ノードの配列が返る
var nodeArray = $.parseHTML('<img src="./serval-chan.jpg" alt="サーバルちゃん">すっごーい！<span>なにそれなにそれー！</span>');

nodeArray.forEach(function (node) {
  console.log(node.nodeName + ': ' + (node.outerHTML || node.textContent));
});
// "IMG: <img src="./serval-chan.jpg" alt="サーバルちゃん">"
// "#text: すっごーい！"
// "SPAN: <span>なにそれなにそれー！</span>"
```

```js:jQueryを使わない例
function parseHTML(html) {
  var tempBody = document.implementation.createHTMLDocument('').body;
  tempBody.innerHTML = html;
  return tempBody.childNodes;
}

// NodeList が返る
var nodeList = parseHTML('<img src="./serval-chan.jpg" alt="サーバルちゃん">すっごーい！<span>なにそれなにそれー！</span>');

nodeArray.forEach(function (node) {
  console.log(node.nodeName + ': ' + (node.outerHTML || node.textContent));
});
// "IMG: <img src="./serval-chan.jpg" alt="サーバルちゃん">"
// "#text: すっごーい！"
// "SPAN: <span>なにそれなにそれー！</span>"
```

この二つの違いとして、`$.parseHTML()` は要素の配列であり、jQueryを使わない方法では `NodeList` になります。

##$.parseXML()

XML文をXMLドキュメントツリーに変換します。

```js:jQueryを使った例
var
  xmlText = '<xml><title>凸レーション</title><member><name>諸星きらり</name><name>城ヶ崎莉嘉</name><name>赤城みりあ</name></member></xml>',
  xmlDocument = $.parseXML(xmlText);

$('title', xmlDocument).text();  // "凸レーション"

$('member name', xmlDocument).each(function (i, element) {
  console.log(i + ': ' + element.textContent);
});
// "0: 諸星きらり"
// "1: 城ヶ崎莉嘉"
// "2: 赤城みりあ"
```

```js:jQueryを使わない例
var
  xmlText = '<xml><title>凸レーション</title><member><name>諸星きらり</name><name>城ヶ崎莉嘉</name><name>赤城みりあ</name></member></xml>',
  xmlDocument = new DOMParser().parseFromString(xmlText, 'application/xml');

xmlDocument.querySelector('title').textContent;  // "凸レーション"

xmlDocument.querySelectorAll('member name').forEach(function (element, i) {
  console.log(i + ': ' + element.textContent);
});
// "0: 諸星きらり"
// "1: 城ヶ崎莉嘉"
// "2: 赤城みりあ"
```

##$.parseJSON()

JSON形式の文字列をJavaScriptのオブジェクトへ変換します。

```js:jQueryを使った例
var json = '{"string":"たーのしー！","number":123,"array":["大丈夫","夜行性だから！"]}';

var obj = $.parseJSON(json);

// obj は以下のようなオブジェクトになる
obj = {
  array: ['大丈夫', '夜行性だから！'],
  number: 123,
  string: 'たーのしー！',
};
```

```js:jQueryを使わない例
var json = '{"string":"たーのしー！","number":123,"array":["大丈夫","夜行性だから！"]}';

var obj = JSON.parse(json);

// obj は以下のようなオブジェクトになる
obj = {
  array: ['大丈夫', '夜行性だから！'],
  number: 123,
  string: 'たーのしー！',
};
```

##$.makeArray()

配列に似たオブジェクトを純粋な配列に変換します。

以下のような配列に似たオブジェクトがあったとします。

```js:配列に似たオブジェクトたち
var
  // オブジェクト
  likeArray = {0: '島村卯月', 1: '渋谷凛', 2: '本田未央', length: 3},

  // HTMLCollection
  htmlCollection = document.getElementsByTagName('*'),

  // NodeList
  nodeList = document.querySelectorAll('*');
```

これらを配列に変換します。

```js:jQueryを使った例
// オブジェクト
likeArray = $.makeArray(likeArray);  // ['島村卯月', '渋谷凛', '本田未央']
$.isArray(likeArray);  // true

// HTMLCollection
htmlCollection = $.makeArray(htmlCollection);  // [html, head, ...]
$.isArray(htmlCollection);  // true

// NodeList
NodeList = $.makeArray(nodeList);  // [html, head, ...]
$.isArray(nodeList);  // true
```

```js:jQueryを使わない例
// Array.prototype.slice を利用する
makeArray = Array.prototype.slice;

// オブジェクト
likeArray = makeArray.call(likeArray);  // ['島村卯月', '渋谷凛', '本田未央']
Array.isArray(likeArray);  // true

// HTMLCollection
htmlCollection = makeArray.call(htmlCollection);  // [html, head, ...]
Array.isArray(htmlCollection);  // true

// NodeList
NodeList = makeArray.call(nodeList);  // [html, head, ...]
Array.isArray(nodeList);  // true
```

ECMAScript 2015 では `Array.from()` が使用できます。

```js:Array.from()を使用した例
// オブジェクト
likeArray = Array.from(likeArray);  // ['島村卯月', '渋谷凛', '本田未央']
Array.isArray(likeArray);  // true

// HTMLCollection
htmlCollection = Array.from(htmlCollection);  // [html, head, ...]
Array.isArray(htmlCollection);  // true

// NodeList
NodeList = Array.from(nodeList);  // [html, head, ...]
Array.isArray(nodeList);  // true
```

##$.proxy()

関数内で実行されるthisを任意のオブジェクトにします。

```js:jQueryを使った例
var individuals = {cute: '早坂美玲', cool: '森久保乃々', passion: '星輝子'};

function getMember(type) {
  'use strict';

  if (typeof this === 'undefined') {
    return null;
  }

  return this[type];
}

// そのままでは this には何も入らない
getMember('cool');                    // null

// Function.prototype.call() を使う
getMember.call(individuals, 'cool');  // "森久保乃々"

// $.proxy() を使う
var getIndividualsMember = $.proxy(getMember, individuals);
getIndividualsMember('cool');         // "森久保乃々"
```

`Function.prototype.bind()` を使用します。

```js:jQueryを使わない例
var individuals = {cute: '早坂美玲', cool: '森久保乃々', passion: '星輝子'};

function getMember(type) {
  'use strict';

  if (typeof this === 'undefined') {
    return null;
  }

  return this[type];
}

// そのままでは this には何も入らない
getMember('cool');                    // null

// Function.prototype.call() を使う
getMember.call(individuals, 'cool');  // "森久保乃々"

// Function.prototype.bind() を使う
var getIndividualsMember = getMember.bind(individuals);
getIndividualsMember('cool');         // "森久保乃々"
```

##$.globalEval()

グローバル空間で文字列のJavaScriptコードを実行させます。（使用注意）

```js:jQueryを使った例
$.globalEval("function goodMorning() {console.log('煩わしい太陽ね');}");

goodMorning();  // "煩わしい太陽ね"
```

```js:jQueryを使わない例
function globalEval(code) {
  var script = document.head.appendChild(document.createElement('script'));
  script.text = code.trim();
  document.head.removeChild(script);
}

globalEval("function goodMorning() {console.log('煩わしい太陽ね');}");

goodMorning();  // "煩わしい太陽ね"
```

##$.trim()

文字列の前後の改行や空白等を削除します。

```js:jQueryを使った例
var ranko = '   \n\n 我が友よ！\n煩わしい太陽ね！\n\n我に力を！  \n  ';

$.trim(ranko);
/*
"我が友よ！↵
煩わしい太陽ね！↵
↵
我に力を！"
*/
```

`String.prototype.trim()` を使用します。

```js:jQueryを使わない例
var ranko = '   \n\n 我が友よ！\n煩わしい太陽ね！\n\n我に力を！  \n  ';

ranko.trim();
/*
"我が友よ！↵
煩わしい太陽ね！↵
↵
我に力を！"
*/
```

##$.now()

現在の時刻（UNIX時間）を返します。

```js:jQueryを使った例
$.now();  // 例えば 1490094881993
```

```js:jQueryを使わない例
Date.now();  // 例えば 1490094881993
```

##$.noop()

空の関数を返します。

```js:jQueryを使った例
$.noop;    // function () {}

$.noop();  // undefined
```

```js:jQueryを使わない例
var noop = function () {};

noop;    // function () {}

noop();  // undefined
```

##$.ajax()

Ajax通信を行うメソッドです。

```js:jQueryを使った例
// get_text.php からテキストを受け取る
$.ajax({
  type: 'get',
  url: './get_text.php',
}).done(function (text) {
  console.log(text);
}).fail(function () {
  console.log('失敗したよ');
});

// post.php にテキストを送信
$.ajax({
  type: 'post',
  url: './post.php',
  data: {
    text: 'ラッキーさん、僕はお客さんじゃないよ',
  },
}).done(function () {
  console.log('送信完了');
}).fail(function () {
  console.log('失敗したよ');
});
```

ECMAScript 2015 の `Promise` が使える前提です。（ポリフィルは探せばあると思います）
かなり省いてます。（そしてあまり自信ない）

```js:jQueryを使わない例
function ajax(url, type, data) {
  return new Promise(function (resolve, reject) {
    var
      xhr = new XMLHttpRequest(),
      params = '';

    type = type || 'get';

    if (data) {
      for (key in data) {
        params += encodeURIComponent(key) + '=' + encodeURIComponent(data[key]) + '&';
      }
      params = params.slice(0, -1);
    }

    xhr.onload = function () {
        if (xhr.status >= 200 && xhr.status < 400) {
          resolve(xhr.responseText);
        } else {
          reject(new Error(xhr.statusText));
        }
    };

    xhr.onerror = function () {
      reject(new Error(xhr.statusText));
    };

    if (type.toLowerCase() === 'post') {
      xhr.open('post', url, true);
      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
      xhr.send(params);
    } else {
      if (params) {
        url += '?' + params;
      }
      xhr.open('get', url, true);
      xhr.send();
    }
  });
}

// get_text.php からテキストを受け取る
ajax('./get_text.php', 'get').then(function (text) {
  console.log(text);
}, function () {
  console.log('失敗したよ');
});

// post.php にテキストを送信
ajax('./post.php', 'post', {
  text: 'ラッキーさん、僕はお客さんじゃないよ',
}).then(function () {
  console.log('送信完了');
}, function () {
  console.log('失敗したよ');
});
```

Fetch APIが使える場合はもっと簡単に書けます。が、まだ本格的には使えなさそう。

```js:Fetchを使った例
// get_text.php からテキストを受け取る
fetch('./get_text.php').then(function(response) {
  // 文字列で受け取る
  return response.text();
}, function () {
  console.log('失敗したよ');
}).then(function(text) {
  console.log(text);
});

// post.php にテキストを送信
fetch('./post.php', {
  method: 'post',
  body: new URLSearchParams('text=ラッキーさん、僕はお客さんじゃないよ'),
}).then(function () {
  console.log('送信完了');
}, function () {
  console.log('失敗したよ');
});
```

Ajax通信の中断やテキスト以外の扱い等については省略します。

#DOM操作系メソッド

jQueryといえばやはりこちらがメインですよね。よく使いそうなものだけ取り上げています。

##$(function () {}), $(document).ready(function () {})

DOM構築が完了した後に実行します。これをやらないとうまく要素が取得できない原因になります。

```js:jQueryを使った例
// 通常
$(function () {
  // do something
});

// 非推奨
$(document).ready(function () {
  // do something
});
```

```js:jQueryを使わない例
document.addEventListener('DOMContentLoaded', function () {
  // do something
});
```

`document.addEventListener('load', function () {});` では、外部ファイルがすべて読み込みが完了するまで実行されないので、意図した動作にならない可能性があります。

##$('&lt;tag&gt;'), $('&lt;tag attribute="value"&gt;content&lt;/tag&gt;')

新しいHTML要素を生成します。
配列に似たjQueryオブジェクトが返ります。

```js:jQueryを使った例
// span要素の生成
$('<span>');
$('<span/>');
$('<span></span>');

// 中にテキストを含めたp要素の生成
$('<p>よぉこそぉ↑ジャパリカフェへ〜！</p>');
$('<p>').text('よぉこそぉ↑ジャパリカフェへ〜！');

// img要素の生成
$('<img src="./japaripark.jpg" alt="ジャパリパーク">');
$('<img>').attr({
  src: './japaripark.jpg',
  alt: 'ジャパリパーク',
});

// 生成した要素を #targetBlock に追加
$('<div>どうぞどうぞ！ ゆっぐりしていってぇ！</div>').appendTo('#targetBlock');
```

```js:jQueryを使わない例
// span要素の生成
var span = document.createElement('span');

// 中にテキストを含めたp要素の生成
var paragraph = document.createElement('p');
paragraph.textContent = 'よぉこそぉ↑ジャパリカフェへ〜！';

// img要素の生成（パターン1）
var img01 = document.createElement('img');
img01.src = './japaripark.jpg';
img01.alt = 'ジャパリパーク';

// img要素の生成（パターン2）
var img02 = new Image();
img02.src = './japaripark.jpg';
img02.alt = 'ジャパリパーク';

// 生成した要素を #targetBlock に追加
var div = document.createElement('div');
div.textContent = 'どうぞどうぞ！ ゆっぐりしていってぇ！';
document.getElementById('targetBlock').appendChild(div);
```

##$('selector')

HTML要素を取得する方法です。CSSセレクタのように書けるので非常に便利ですよね。
配列に似たjQueryオブジェクトが返ります。

```js:jQueryを使った例
// idが "mainFooter" の要素を取得
$('#mainFooter');

// class名が "entries" の要素を取得
$('.entries');

// div要素を取得
$('div');

// article要素の子要素であるp要素を取得
$('article p');
$('article').find('p');

// ul要素とol要素の取得
$('ul, ol');

// チェックが付いたinput要素の取得
$('input:checked');
$('input').filter(':checked');

// target属性のないa要素を取得
$('a:not([target])');
$('a').not('[target]');
```

JavaScriptでは様々な取得方法があります。
`document.getElementById` と `document.querySelector` はHTML要素が、それ以外は配列に似た `HTMLCollection` や `NodeList` が返ります。

```js:jQueryを使わない例
// idが "mainFooter" の要素を取得
document.getElementById('mainFooter');       // 処理が速い
document.querySelector('#mainFooter');

// class名が "entries" の要素を取得
document.getElementsByClassName('entries');  // 処理が速い
document.querySelectorAll('.entries');

// div要素を取得
document.getElementsByTagName('div');        // 処理が速い
document.querySelectorAll('div');

// article要素の子要素であるp要素を取得
document.querySelectorAll('article p');

// ul要素とol要素の取得
document.querySelectorAll('ul, ol');

// チェックが付いたinput要素の取得
document.querySelectorAll('input:checked');

// target属性のないa要素を取得
document.querySelectorAll('a:not([target])');
```

`document.querySelectorAll` がほぼ同じ働きをしてくれています。

`document.getElementsByTagName` や `document.getElementsByClassName` が返す `HTMLCollection` は動的な要素のリストで、`document.querySelectorAll` が返す `NodeList` は静的な要素のリストです。
何が違うのかというと、操作している途中で要素が追加されたりすると `HTMLCollection` の中身と `length` が変化するのに対して、`NodeList` は取得した当時の値を保持したままです。なので、扱いに注意が必要です。

また、`NodeList` は配列の `Array.prototype.forEach()` と同じように `NodeList.forEach()` が使用可能です。
以降、複数パターンを書くと煩雑になるので、基本的に単体のHTML要素の取得には `document.querySelector` を、複数のHTML要素の取得には `document.querySelectorAll` を使用する方法で解説します。
（実際には状況によって `document.getElementById`, `document.getElementsByTagName`, `document.getElementsByClassName` なども使い分けるなどしましょう）

##.each()

取得した要素のループ処理を行うメソッドです。

```js:jQueryを使った例
// '.article p' のループ処理
$('.article p').each(function (i, element) {
  // do something
});
```

`NodeList.forEach()` が使えます。引数がjQueryと逆なので注意。

```js:jQueryを使わない例
// '.article p' のループ処理
document.querySelectorAll('.article p').forEach(function (element, i) {
  // do something
});
```

IEなどでは `NodeList.forEach()` が使えないので、`Array.prototype.forEach()` で代用ができます。

```js:NodeList.forEach()が使えない場合
/* Array.prototype.forEach.call() でなんとかする */
var forEach = Array.prototype.forEach;

// '.article p' のループ処理
forEach.call(document.querySelectorAll('.article p'), function (element, i) {
  // do something
});

/* いっその事同じコードで書けるようにする */
if (!NodeList.prototype.forEach) {
  NodeList.prototype.forEach = Array.prototype.forEach;
}

// '.article p' のループ処理
document.querySelectorAll('.article p').forEach(function (element, i) {
  // do something
});
```

ちなみに、`NodeList` は ECMAScript 2015 の `for...of` 文も使用できます。

以降のコードでは、`NodeList.forEach()` を使用します。

##.find()

子要素（孫要素、ひ孫要素なども含む）を取得します。

```js:jQueryを使った例
// #mainNavigation の li を取得
$('#mainNavigation').find('li');

// .entries の h2 と h3 を取得
$('.entries').find('h2, h3');

/* 本来ならばこのように書く方がわかりやすい */
// #mainNavigation の li を取得
$('#mainNavigation li');

// .entries の h2 と h3 を取得
$('.entries h2, .entries h3');
```

```js:jQueryを使わない例
/* あえて複雑な書き方をする場合 */
// #mainNavigation の li を取得（4通り）
document.getElementById('mainNavigation').getElementsByTagName('li');  // 処理が速い
document.getElementById('mainNavigation').querySelectorAll('li');
document.querySelector('#mainNavigation').getElementsByTagName('li');
document.querySelector('#mainNavigation').querySelectorAll('li');

// .entries の h2 と h3 を取得（配列にHTML要素を入れる方法）
var elements = [];
document.querySelectorAll('.entries').forEach(function (element) {
  elements.push.apply(elements02, element.querySelectorAll('h2, h3'));
});
/// elements に h2 と h3 が入る

/* 本来ならばこのように書く方がわかりやすい */
// #mainNavigation の li を取得
document.querySelectorAll('#mainNavigation li');

// .entries の h2 と h3 を取得
document.querySelectorAll('.entries h2, .entries h3');
```

##.html(), .text(), .empty()

指定した要素内のHTMLやテキストを取得・変更・空にします。

```js:jQueryを使った例
var $welcome = $('#welcome');

// .welcome 内のHTMLを取得
$welcome.html();  // 例えば "<b>ようこそ！</b>"

// .welcome 内のテキストを取得
$welcome.text();  // 例えば "ようこそ！"

// .welcome 内のHTMLを変更
$welcome.html('<b>いらっしゃぁい！</b>');

// .welcome 内のテキストを変更
$welcome.text('よぉこそぉ↑ジャパリカフェへ〜！');

// .welcome 内を空にする
$welcome.empty();
```

```js:jQueryを使わない例
var welcome = document.querySelector('#welcome');

// .welcome 内のHTMLを取得
welcome.innerHTML;  // 例えば "<b>ようこそ！</b>"

// .welcome 内のテキストを取得
welcome.textContent;  // 例えば "ようこそ！"

// .welcome 内のHTMLを変更
welcome.innerHTML = '<b>いらっしゃぁい！</b>';

// .welcome 内のテキストを変更
welcome.textContent = 'よぉこそぉ↑ジャパリカフェへ〜！';

// .welcome 内を空にする
welcome.textContent = '';
```

##.attr(), .removeAttr()

要素の属性の値を取得、属性の追加・変更・削除を行います。

```js:jQueryを使った例
// #mainImage のalt属性を取得
$('#mainImage').attr('alt');  // 例えば "けものフレンズ"

// .targetLink にtarget属性を追加する
$('.targetLink').attr('target', '_blank');
$('.targetLink').attr({target: '_blank'});

// .targetLink のtarget属性を取り除く
$('.targetLink').removeAttr('target');
```

```js:jQueryを使わない例
// #mainImage のalt属性を取得
document.querySelector('#mainImage').getAttribute('alt');  // 例えば "けものフレンズ"

// .targetLink にtarget属性を追加する
document.querySelectorAll('.targetLink').forEach(function (element) {
  element.setAttribute('target', '_blank');
});

// .targetLink のtarget属性を取り除く
document.querySelectorAll('.targetLink').forEach(function (element) {
  element.removeAttribute('target');
});
```

##.addClass(), .removeClass(), .toggleClass(), .hasClass()

要素のクラス名関係の操作です。

```js:jQueryを使った例
var $elements = $('li a');

// 'li a' にクラス 'listLink' を追加
$elements.addClass('listLink');

// 'li a' のクラス 'listLink' を削除
$elements.removeClass('listLink');

// 'li a' のクラス 'listLink' がない場合は追加し、ある場合は削除する
$elements.toggleClass('listLink');

// #targetBlock にクラス 'listLink' が存在するかの真偽値
$('#targetBlock').hasClass('listLink');  // 例えば "false"
```

```js:jQueryを使わない例
var elements = document.querySelectorAll('li a');

// 'li a' にクラス 'listLink' を追加
elements.forEach(function (element) {
  element.classList.add('listLink');
});

// 'li a' のクラス 'listLink' を削除
elements.forEach(function (element) {
  element.classList.remove('listLink');
});

// 'li a' のクラス 'listLink' がない場合は追加し、ある場合は削除する
elements.forEach(function (element) {
  element.classList.toggle('listLink');
});

// #targetBlock にクラス 'listLink' が存在するかの真偽値
document.querySelector('#targetBlock').classList.contains('listLink');  // 例えば "false"
```

##.css()

要素のスタイルを取得したり、スタイルを適用します。

```js:jQueryを使った例
// 最初に取得できる .redBox のスタイルを取得
$('.redBox').css('background-color');  // 例えば "rgb(255, 0, 0)"
$('.redBox').css('backgroundColor');   // 例えば "rgb(255, 0, 0)"

// .targetBox にスタイルを適用
$('.targetBox').css('margin-bottom', 50);
$('.targetBox').css('marginBottom', 50);
$('.targetBox').css({'margin-bottom': 50});
$('.targetBox').css({marginBottom: 50});
```

```js:jQueryを使わない例
// 最初に取得できる .redBox のスタイルを取得
var
  redBox = document.querySelector('.redBox'),
  redBoxStyle = window.getComputedStyle(redBox);   // getComputedStyle を使う

redBoxStyle.backgroundColor;                       // 例えば "rgb(255, 0, 0)"
redBoxStyle.getPropertyValue('background-color');  // 例えば "rgb(255, 0, 0)"

// .targetBox にスタイルを適用
document.querySelectorAll('.targetBox').forEach(function (element) {
  element.style.marginBottom = '50px';

  // チェインケースの場合
  // element.style.setProperty('margin-bottom', '50px');
});
```

`window.getComputedStyle()` については、自分が前に書いたものを見てもらうと分かると思います。
[window.getComputedStyle() で要素のスタイルを取得する](http://qiita.com/sdn_tome/items/bb79bec002a6ff033810)

##.prop()

要素のプロパティを取得・変更します。

```js:jQueryを使った例
// 取得した要素の nodeName を取得する
$('.mainArticle').prop('nodeName');  // 例えば "ARTICLE"

// 2番目のチェックボックスにチェックを入れる
$('input[type="checkbox"]').eq(1).prop('checked', true);
$('input[type="checkbox"]').eq(1).prop({checked: true});

// 複数のテキストフォームを空にして disabled にする
$('input[type="text"]').prop({
  value: '',
  disabled: true,
});
```

```js:jQueryを使わない例
// 取得した要素の nodeName を取得する
var mainArticle = document.querySelector('.mainArticle');
mainArticle.nodeName;  // 例えば "ARTICLE"

// 2番目のチェックボックスにチェックを入れる
var checkbox = document.querySelectorAll('input[type="checkbox"]');
checkbox[1].checked = true;

// 複数のテキストフォームを空にして disabled にする
var inputText = document.querySelectorAll('input[type="text"]');
inputText.forEach(function (element) {
  element.value = '';
  element.disabled = true;
});
```

##.data()

要素に紐づけられたデータを設定・取得します。

このメソッドは要素の `data-*` 属性の値を取得しますが、jQueryは独自にデータを管理するので**完全な互換性があるわけではありません**。
jQueryでは文字列だけでなく数値や配列、オブジェクトといったものも紐づけられるのに対し、ネイティブな実装ではすべて文字列として扱われます。

以下のようなHTMLがあったとします。

```html:Before
<div id="toki" data-name="Japanese crester ibis" data-cites-year="1973">わたしはトキ 仲間を探してる どこにいるの仲間たち</div>
```

```js:jQueryを使った例
var $toki = $('#toki');

// data-name の値を取得
$toki.data('name');  // "Japanese crester ibis"

$.type($toki.data('name'));  // "string"

// data-cites-year の値を取得
$toki.data('citesYear');   // 1973
$toki.data('cites-year');  // 1973

$.type($toki.data('citesYear'));  // "number"

// classification という名前のデータの追加（オブジェクトを追加）
$toki.data('classification', {
  class: 'Aves',
  order: 'Pelecaniformes',
  family: 'Threskiornithidae',
});

$.type($toki.data('classification'));  // "object"

// #toki に紐づけられたデータを取得
var tokiData = $toki.data();

// tokiData は以下のようなオブジェクトが入っている
tokiData = {
  name: 'Japanese crester ibis',
  citesYear: 1973,
  classification: {
    class: 'Aves',
    order: 'Pelecaniformes',
    family: 'Threskiornithidae',
  },
};
```

```js:jQueryを使わない例
var toString = Object.prototype.toString;
function typeOf(obj) {
  return toString.call(obj).slice(8, -1).toLowerCase();
}

var toki = document.querySelector('#toki');

// data-name の値を取得
toki.dataset.name;  // "Japanese crester ibis"

typeOf(toki.dataset.name);  // "string"

// data-cites-year の値を取得
toki.dataset.citesYear;  // "1973"

typeOf(toki.dataset.citesYear);  // "string" ←！！

// classification という名前のデータの追加（オブジェクトを追加してみる）
toki.dataset.classification = {
  class: 'Aves',
  order: 'Pelecaniformes',
  family: 'Threskiornithidae',
};

typeOf(toki.dataset.classification);  // "string" ←！！

// #toki に紐づけられたデータを取得
var tokiData = toki.dataset;

// tokiData は以下のような DOMStringMap という名前のオブジェクトが入っている
tokiData = {
  name: 'Japanese crester ibis',
  citesYear: '1973',
  classification: '[object Object]',  // object は文字列に変換されるため
};
```

`HTMLElement.dataset` は文字列しか扱えないのがわかります。

##.eq()

n番目の要素を取り出します。

```js:jQueryを使った例
var $lists = $('#linkList li');

// '#linkList li' の4つ目を取り出す
$lists.eq(3);

// '#linkList li' の後ろから2つ目を取り出す
$lists.eq(-2);
```

```js:jQueryを使わない例
var lists = document.querySelectorAll('#linkList li');

// '#linkList li' の4つ目を取り出す
lists[3];

// '#linkList li' の後ろから2つ目を取り出す
lists[lists.length - 2];
```

##.index()

指定した要素が取得した要素の何番目にあるかを調べます。

以下のようなHTMLがあったとします、

```html:HTML
<ul class="ppp">
  <li class="royal">プリンセス</li>
  <li class="emperor">コウテイ</li>
  <li class="gentoo">ジェーン</li>
  <li class="rockhopper">イワビー</li>
  <li class="humboldt">フルル</li>
</ul>
```

```js:jQueryを使った例
var $rockhopper = $('.rockhopper');

$('.ppp li').index($rockhopper);  // 3
```

`Array.prototype.indexOf` を利用します。

```js:jQueryを使わない例
var indexOf = Array.prototype.indexOf;

var rockhopper = document.querySelector('.rockhopper');

indexOf.call(document.querySelectorAll('.ppp li'), rockhopper);  // 3
```

##.slice()

指定した範囲の要素リストを作ります。

以下のようなHTMLがあったとします、

```html:HTML
<ul class="ppp">
  <li class="royal">プリンセス</li>
  <li class="emperor">コウテイ</li>
  <li class="gentoo">ジェーン</li>
  <li class="rockhopper">イワビー</li>
  <li class="humboldt">フルル</li>
</ul>
```

```js:jQueryを使った例
var $ppp = $('.ppp li');

$ppp.slice(1, 3);
// [li.emperor, li.gentoo] のjQueryオブジェクトになる

$ppp.slice(-2);
// [li.rockhopper, li.humboldt] のjQueryオブジェクトになる

$ppp.slice(0, -3);
// [li.royal, li.emperor] のjQueryオブジェクトになる
```

`Array.prototype.slice` を利用します。

```js:jQueryを使わない例
var slice = Array.prototype.slice;

var ppp = document.querySelectorAll('.ppp li');

slice.call(ppp, 1, 3);
// [li.emperor, li.gentoo] の配列になる

slice.call(ppp, -2);
// [li.rockhopper, li.humboldt] の配列になる

slice.call(ppp, 0, -3);
// [li.royal, li.emperor] の配列になる
```

##.first(), .last()

取得した要素リストの最初・最後の要素を取り出します。

```js:jQueryを使った例
var $lists = $('#linkList li');

// '#linkList li' の最初の要素を取り出す
$lists.first();

// '#linkList li' の最後の要素を取り出す
$lists.last();
```

```js:jQueryを使わない例
var lists = document.querySelectorAll('#linkList li');

// '#linkList li' の最初の要素を取り出す
lists[0];

// '#linkList li' の最後の要素を取り出す
lists[lists.length - 1];
```

##.filter(), .not()

取得した要素リストを特定の条件に当てはまる・当てはまらないかでフィルタリングします。

```js:jQueryを使った例
var $variousElement = $('.variousElement');

// .variousElement で span のみを取得
$('.variousElement').filter('span');

// .variousElement で span 以外を取得
$('.variousElement').not('span');

var $input = $('input');

// input属性の :checked のみを取得
$('input').filter(':checked');

// input属性の :disabled 以外を取得
$('input').not(':disabled');

/* 本来ならばこのように書く方がわかりやすい */
// input属性の :checked のみを取得
$('input:checked');

// input属性の :disabled 以外を取得
$('input:not(:disabled)');
```

```js:jQueryを使わない例
// .variousElement で span のみを取得
document.querySelectorAll('span.variousElement');

// .variousElement で span 以外を取得
document.querySelectorAll('.variousElement:not(span)');

// input属性の :checked のみを取得
document.querySelectorAll('input:checked');

// input属性の :disabled 以外を取得
document.querySelectorAll('input:not(:disabled)');
```

##.has()

指定した要素を子に持つ要素だけを取得します。

以下のようなHTMLがあったとします。

```html:HTML
<ul class="words">
  <li>おいしいものを食べてこその人生なのです</li>
  <li>へーき、へーき！<br>フレンズによって得意なこと違うから！</li>
  <li>がおー！ たべちゃうぞー！</li>
  <li>早く追いかけるのだ！<br>パークの危機なのだ！</li>
  <li>アライさん、またやってしまったねぇ</li>
</ul>
```

br要素を持つli要素だけ取得してみます。

```js:jQueryを使った例
var $hasBreak = $('.words li').has('br');

$hasBreak.each(function (i, element) {
  console.log(element.textContent);
});
// "へーき、へーき！フレンズによって得意なこと違うから！"
// "早く追いかけるのだ！パークの危機なのだ！"
```

```js:jQueryを使わない例
var filter = Array.prototype.filter;

var words = document.querySelectorAll('.words li');

var hasBreak = filter.call(words, function (element) {
  return !!element.querySelector('br');
});

hasBreak.forEach(function (element) {
  console.log(element.textContent);
});
// "へーき、へーき！フレンズによって得意なこと違うから！"
// "早く追いかけるのだ！パークの危機なのだ！"
```

##.children()

要素の直下にある子要素を取得します。

```js:jQueryを使った例
// .entries 直下の子要素を取得
$('.entries').children();

// .entries 直下の div を取得
$('.entries').children('div');

/* 本来ならばこのように書く方がわかりやすい */
// .entries 直下の子要素を取得
$('.entries > *');

// .entries 直下の div を取得
$('.entries > div');
```

```js:jQueryを使わない例
// .entries 直下の子要素を取得
document.querySelectorAll('.entries > *');

// .entries 直下の div を取得
document.querySelectorAll('.entries > div');
```

##.parent()

要素の親要素を取得します。

```js:jQueryを使った例
// .children の親要素の取得
$('.children').parent();
```

```js:jQueryを使わない例
// .children の親要素の取得
var parents = [];
document.querySelectorAll('.children').forEach(function (element) {
  parents.push(element.parentNode);
});

/// 重複しているかもしれないので filter を使う
parents = parents.filter(function (element, i) {
  return parents.indexOf(element) === i;
});
```

##.parents()

現在の要素から &lt;html&gt; まで遡ります。

以下のようなHTMLがあったとします。

```html:HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>テスト</title>
</head>
<body>
<ul class="level1">
  <li class="level1-1">わたしはトキ 仲間を探してる</li>
  <li class="level1-2">どこにいるの仲間たち
    <ul class="level2">
      <li class="level2-1">わたしの仲間探してくださいあ あ仲間……</li>
    </ul>
  </li>
</ul>
</body>
</html>
```

```js:jQueryを使った例
// .level2-1 からさかのぼっていく
var $parents = $('.level2-1').parents();

// $parents はこのようなリストになる（実際にはjQueryオブジェクトです）
// {0: ul.level2, 1: li.level1-2, 2: ul.level1, 3: body, 4: html}
```

```js:jQueryを使わない例
// .level2-1 からさかのぼっていく
var
  cursor = document.querySelector('.level2-1').parentNode,
  parents = [];

for (; !!cursor && cursor.nodeType !== 9; cursor = cursor.parentNode) {
  parents.push(cursor);
}

// parents はこのような配列になる
// [ul.level2, li.level1-2, ul.level1, body, html]
```

##.closest()

現在の要素から最初にマッチする要素まで遡ります。

以下のようなHTMLがあったとします。

```html:HTML
<ul class="level1">
  <li class="level1-1">わたしはトキ</li>
  <li class="level1-2 find">仲間を探してる
    <ul class="level2">
      <li class="level2-1 where">どこにいるの仲間たち</li>
      <li class="level2-2 find">わたしの仲間探してください
        <ul class="level3">
          <li class="level3-1">ああ仲間……</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>
```

```js:jQueryを使った例
// この場合 ul.level3 になる
$('.level3-1').closest('ul');

// この場合 li.level2-2 になる
$('.level3-1').closest('.find');

// この場合 li.level1-2 になる
$('.level2-1').closest('.find');

// 何も取得しない
$('.level3-1').closest('.where');
$('.level1-1').closest('li');

// 自分自身を取得
$('.level2-1').closest('li');
$('.level3-1').closest('li');
```

`Element.closest()` を使用します。

```js:jQueryを使わない例
// Element.closest() を利用するが、対応していないIE/Edgeのためにポリフィルも用意する
if (!Element.prototype.closest) {
  Element.prototype.closest = function (selector) {
    var closest = null;
    for (var cursor = this; !!cursor && cursor.nodeType !== 9; cursor = cursor.parentNode) {
      if (cursor.msMatchesSelector(selector)) {
        closest = cursor;
        break;
      }
    }
    return closest;
  };
}

// この場合 ul.level3 になる
document.querySelector('.level3-1').closest('ul');

// この場合 li.level2-2 になる
document.querySelector('.level3-1').closest('.find');

// この場合 li.level1-2 になる
document.querySelector('.level2-1').closest('.find');

// 何も取得しない
document.querySelector('.level3-1').closest('.where');
document.querySelector('.level1-1').closest('li');

// 自分自身を取得
document.querySelector('.level2-1').closest('li');
document.querySelector('.level3-1').closest('li');
```

##.next(), .prev()

要素の前後にある要素を取得します。

```js:jQueryを使った例
// .target の後にある要素の取得
$('.target').next();

// .target の前にある要素の取得
$('.target').prev();
```

```js:jQueryを使わない例
// .target の後にある要素の取得
document.querySelectorAll('.target + *');

// .target の後にある要素の取得その2（nextElements に入る）
var nextElements = [];
document.querySelectorAll('.target').forEach(function (element) {
  if (element.nextElementSibling) {
    nextElements.push(element.nextElementSibling);
  }
});

// .target の前にある要素の取得（prevElements に入る）
var prevElements = [];
document.querySelectorAll('.target').forEach(function (element) {
  if (element.previousElementSibling) {
    prevElements.push(element.previousElementSibling);
  }
});
```

##.siblings(), .nextAll(), .prevAll()

自分以外の兄弟要素を取得します。

以下のようなHTMLがあったとします。

```html:HTML
<ul>
  <li class="item01">わたしはトキ</li>
  <li class="item02">仲間を探してる</li>
  <li class="item03">どこにいるの</li>
  <li class="item04">仲間たち</li>
  <li class="item05">わたしの仲間</li>
  <li class="item06">さがしてください</li>
  <li class="item07">ああ仲間……</li>
</ul>
```

```js:jQueryを使った例
var $item04 = $('.item04');

// .item04 の兄弟要素を取得
$item04.siblings();  // li.item04 以外のli要素のリストになる

// .item04 から後の兄弟要素の取得
$item04.nextAll();  // [li.item05, li.item06, li.item07]

// .item04 より前の兄弟要素の取得
$item04.prevAll();  // [li.item03, li.item02, li.item01]
```

```js:jQueryを使わない例
var array = Array.prototype;

var item04 = document.querySelector('.item04');

// .item04 の兄弟要素を取得
var siblings = array.filter.call(item04.parentNode.children, function (element) {
  return element !== item04;
});
/// siblings は li.item04 以外のli要素の配列になる

// .item04 から後の兄弟要素の取得（簡単な記述）
document.querySelectorAll('.item04 ~ *');  // [li.item05, li.item06, li.item07]

// .item04 から後の兄弟要素の取得（複雑な記述の例）
var nextAll = array.slice.call(item04.parentNode.children, array.indexOf.call(item04.parentNode.children, item04) + 1);
console.log(nextAll);  // [li.item05, li.item06, li.item07]

// .item04 より前の兄弟要素の取得
var prevAll = array.slice.call(item04.parentNode.children, 0, array.indexOf.call(item04.parentNode.children, item04)).reverse();
console.log(prevAll);  // [li.item03, li.item02, li.item01]
```

##.clone()

要素を複製します。

```js:jQueryを使った例
// .sampleElement を複製
$('.sampleElement').clone();
```

```js:jQueryを使わない例
// .sampleElement を複製（cloneElements に入る）
var cloneElements = [];
document.querySelectorAll('.sampleElement').forEach(function (element) {
  cloneElements.push(element.cloneNode(true));
});

// .sampleElement（単体）を複製
document.querySelector('.sampleElement').cloneNode(true);
```

##.remove()

要素をDOMから取り除きます。（削除ではない）

```js:jQueryを使った例
// .ignore を取り除く
$('.ignore').remove();
```

```js:jQueryを使わない例
// .ignore を取り除く
document.querySelectorAll('.ignore').forEach(function (element) {
  element.parentNode.removeChild(element);

  // IE以外のブラウザではこの方法も使える
  // element.remove();
});
```

##.before(), .prepend(), .append(), .after()

指定した要素にHTMLや要素を挿入します。

以下のようなHTMLがあったとします。

```html:Before
<p id="naninomu">ねえなんにぃのんむぅ</p>
<div id="targetBlock">
  <p>ゆっぐりしてってぇ！</p>
</div>
```

これにいろいろ挿入してみます。

```js:jQueryを使った例
var $targetBlock = $('#targetBlock');

// #targetBlock の前にHTMLを挿入
$targetBlock.before('<p id="p01">ふわああぁ！</p>');

// #targetBlock 内の先頭にHTMLを挿入
$targetBlock.prepend('<p id="p02">どうぞどうぞ！</p>');

// #targetBlock 内の一番後ろにHTMLを挿入
$targetBlock.append('<p id="p03">いやま゛っ↓てたよぉ！</p>');

// #targetBlock の後ろにHTMLを挿入
$targetBlock.after('<p id="p04">色々あるよぉ</p>');

// #targetBlock の前に、生成した要素を挿入
var $paragraph01 = $('<p id="p05">いらっしゃぁい！</p>');
$targetBlock.before($paragraph01);

// #targetBlock 内の先頭に、生成した要素を挿入
var $paragraph02 = $('<p id="p06">よぉこそぉ↑ジャパリカフェへ〜！</p>');
$targetBlock.prepend($paragraph02);

// #targetBlock 内の一番後ろに、生成した要素を挿入
var $paragraph03 = $('<p id="p07">やっとお客さんが来てくれたゆぉ！</p>');
$targetBlock.append($paragraph03);

// #targetBlock の後ろに、生成した要素を挿入
var $paragraph04 = $('<p id="p08">嬉しいなあ！</p>');
$targetBlock.after($paragraph04);

// #p08 の後ろに、#naninomu を挿入（移動）
$('#p08').after($('#naninomu'));
```

```js:jQueryを使わない例
var targetBlock = document.querySelector('#targetBlock');

// #targetBlock の前にHTMLを挿入
targetBlock.insertAdjacentHTML('beforebegin', '<p id="p01">ふわああぁ！</p>');

// #targetBlock 内の先頭にHTMLを挿入
targetBlock.insertAdjacentHTML('afterbegin', '<p id="p02">どうぞどうぞ！</p>');

// #targetBlock 内の一番後ろにHTMLを挿入
targetBlock.insertAdjacentHTML('beforeend', '<p id="p03">いやま゛っ↓てたよぉ！</p>');

// #targetBlock の後ろにHTMLを挿入
targetBlock.insertAdjacentHTML('afterend', '<p id="p04">色々あるよぉ</p>');

// #targetBlock の前に、生成した要素を挿入
var paragraph01 = document.createElement('p');
paragraph01.id = 'p05';
paragraph01.textContent = 'いらっしゃぁい！';
targetBlock.parentNode.insertBefore(paragraph01, targetBlock);
/// 「#targetBlock の親要素」内にある子要素の #targetBlock の前に paragraph01 を挿入、ということ

// #targetBlock 内のの先頭に、生成した要素を挿入
var paragraph02 = document.createElement('p');
paragraph02.id = 'p06';
paragraph02.textContent = 'よぉこそぉ↑ジャパリカフェへ〜！';
targetBlock.insertBefore(paragraph02, targetBlock.firstChild);
/// #targetBlock 内にある最初の子要素の前に paragraph01 を挿入、ということ

// #targetBlock 内の一番後ろに、生成した要素を挿入
var paragraph03 = document.createElement('p');
paragraph03.id = 'p07';
paragraph03.textContent = 'やっとお客さんが来てくれたゆぉ！';
targetBlock.appendChild(paragraph03);

// #targetBlock の後ろに、生成した要素を挿入
var paragraph04 = document.createElement('p');
paragraph04.id = 'p08';
paragraph04.textContent = '嬉しいなあ！';
targetBlock.parentNode.insertBefore(paragraph04, targetBlock.nextSibling);
/// 「#targetBlock の親要素」内にある子要素の #targetBlock の
/// 次にあるノード（テキストや要素など）の前に挿入、ということ

// #p08 の後ろに、#naninomu を挿入（移動）
var p08 = document.querySelector('#p08');
p08.parentNode.insertBefore(document.querySelector('#naninomu'), p08.nextSibling);
```

最終的にHTMLはこのような感じになります。

```html:After
<p id="p01">ふわああぁ！</p>
<p id="p05">いらっしゃぁい！</p>
<div id="targetBlock">
  <p id="p06">よぉこそぉ↑ジャパリカフェへ〜！</p>
  <p id="p02">どうぞどうぞ！</p>
  <p>ゆっぐりしてってぇ！</p>
  <p id="p03">いやま゛っ↓てたよぉ！</p>
  <p id="p07">やっとお客さんが来てくれたゆぉ！</p>
</div>
<p id="p08">嬉しいなあ！</p>
<p id="naninomu">ねえなんにぃのんむぅ</p>
<p id="p04">色々あるよぉ</p>
```

このサンプルでは生成した要素を挿入していますが、既にDOM上にある要素も同じように扱えます。

##.insertBefore(), .prependTo(), .appendTo(), .insertAfter()

要素を指定した要素に挿入します。

以下のようなHTMLがあったとします。

```html:Before
<p id="yukkuri">ゆっぐりしてってぇ！</p>
<div id="targetBlock">
  <p>よぉこそぉ↑ジャパリカフェへ〜！</p>
</div>
```

これにいろいろ挿入してみます。

```js:jQueryを使った例
// 生成した要素を #targetBlock の前に挿入
$('<p id="p01">ふわああぁ！</p>').insertBefore('#targetBlock');

// 生成した要素を #targetBlock 内の先頭に挿入
$('<p id="p02">いらっしゃぁい！</p>').prependTo('#targetBlock');

// 生成した要素を #targetBlock 内の一番後ろに挿入
$('<p id="p03">どうぞどうぞ！</p>').appendTo('#targetBlock');

// 生成した要素を #targetBlock の後ろに挿入
$('<p id="p04">いやま゛っ↓てたよぉ！</p>').insertAfter('#targetBlock');
```

```js:jQueryを使わない例
var targetBlock = document.querySelector('#targetBlock');

/* 考えは .before(), .prepend(), .append(), .after() と同じ*/

// 生成した要素を #targetBlock の前に挿入
var paragraph01 = document.createElement('p');
paragraph01.id = 'p01';
paragraph01.textContent = 'ふわああぁ！';
targetBlock.parentNode.insertBefore(paragraph01, targetBlock);

// 生成した要素を #targetBlock 内の先頭に挿入
var paragraph02 = document.createElement('p');
paragraph02.id = 'p02';
paragraph02.textContent = 'いらっしゃぁい！';
targetBlock.insertBefore(paragraph02, targetBlock.firstChild);

// 生成した要素を #targetBlock 内の一番後ろに挿入
var paragraph03 = document.createElement('p');
paragraph03.id = 'p03';
paragraph03.textContent = 'どうぞどうぞ！';
targetBlock.appendChild(paragraph03);

// 生成した要素を #targetBlock の後ろに挿入
var paragraph04 = document.createElement('p');
paragraph04.id = 'p04';
paragraph04.textContent = 'いやま゛っ↓てたよぉ！';
targetBlock.parentNode.insertBefore(paragraph04, targetBlock.nextSibling);

// #p04 の前に、#yukkuri を挿入（移動）
var p04 = document.querySelector('#p04');
p04.parentNode.insertBefore(document.querySelector('#yukkuri'), p04);
```

最終的にHTMLはこのような感じになります。

```html:After
<p id="p01">ふわああぁ！</p>
<div id="targetBlock">
  <p id="p02">いらっしゃぁい！</p>
  <p>よぉこそぉ↑ジャパリカフェへ〜！</p>
  <p id="p03">どうぞどうぞ！</p>
</div>
<p id="yukkuri">ゆっぐりしてってぇ！</p>
<p id="p04">いやま゛っ↓てたよぉ！</p>
```

##.wrap(), .wrapAll(), .wrapInner(), .unwrap()

特定の要素を指定した要素で包んだり、親要素を取り除いたりします。

以下のようなHTMLがあったとします。

```html:Before
<section class="images01">
  <img src="./kaban.jpg" alt="かばん">
  <img src="./serval.jpg" alt="サーバル">
  <img src="./fennec.jpg" alt="フェネック">
  <img src="./common-raccoon.jpg" alt="アライさん">
</section>
<section class="images02">
  <img src="./kaban.jpg" alt="かばん">
  <img src="./serval.jpg" alt="サーバル">
  <img src="./fennec.jpg" alt="フェネック">
  <img src="./common-raccoon.jpg" alt="アライさん">
</section>
```

これにいろいろ操作してみます。

```js:jQueryを使った例
// '.images01 img' をひとつひとつdiv要素で包む
$('.images01 img').wrap('<div>');

// '.images02 img' をまとめてdiv要素で包む
$('.images02 img').wrapAll('<div>');

// .images01 の子要素をspan要素で包む
$('.images01').wrapInner('<span>');

// 'section div' の親要素（要するに section）を取り除く
$('section div').unwrap();
```

```js:jQueryを使わない例
// '.images01 img' をひとつひとつdiv要素で包む
document.querySelectorAll('.images01 img').forEach(function (element) {
  var wrapElement = document.createElement('div');
  element.parentNode.insertBefore(wrapElement, element);
  wrapElement.appendChild(element);
});

// '.images02 img' をまとめてdiv要素で包む
var
  images02 = document.querySelectorAll('.images02 img'),
  wrapElement = document.createElement('div');

images02[0].parentNode.insertBefore(wrapElement, images02[0]);
images02.forEach(function (element) {
  wrapElement.appendChild(element);
});

// '.images01 div' の子要素をspan要素で包む
document.querySelectorAll('.images01 div').forEach(function (element) {
  var span = document.createElement('span');
  element.childNodes.forEach(function (child) {
    span.appendChild(child);
  });
  element.appendChild(span);
});

// 'section div' の親要素（要するに section）を取り除く
var parents = [];

document.querySelectorAll('section div').forEach(function (element) {
  var parent = element.parentNode;
  parents.push(parent);
  parent.parentNode.insertBefore(element, parent);
});

parents.filter(function (element, i) {
  return parents.indexOf(element) === i;
}).forEach(function (element) {
  element.parentNode.removeChild(element);
});
```

最終的にHTMLはこのような感じになります。

```html:After
<div>
  <span><img src="./kaban.jpg" alt="かばん"></span>
</div>
<div>
  <span><img src="./serval.jpg" alt="サーバル"></span>
</div>
<div>
  <span><img src="./fennec.jpg" alt="フェネック"></span>
</div>
<div>
  <span><img src="./common-raccoon.jpg" alt="アライさん"></span>
</div>
<div>
  <img src="./kaban.jpg" alt="かばん">
  <img src="./serval.jpg" alt="サーバル">
  <img src="./fennec.jpg" alt="フェネック">
  <img src="./common-raccoon.jpg" alt="アライさん">
</div>
```

##.is()

要素が指定した状態なのかの真偽値を返します。

以下のようなHTMLがあったとします。

```html:Before
<input id="ppp" class="pppLive" type="text" name="penguins" value="ぺぱぷらいぶ！" disabled>
```

この要素に対していろいろやってみます。

```js:jQueryを使った例
var $ppp = $('#ppp');

$ppp.is('input');             // true
$ppp.is('div');               // false
$ppp.is('.pppLive');          // true
$ppp.is('.ppp');              // false
$ppp.is('[type="radio"]');    // false
$ppp.is('[name="penguin"]');  // true
$ppp.is(':disabled');         // true
$ppp.is(':checked');          // false

// jQuery で使える特殊セレクタ
$ppp.is(':visible');          // true
$ppp.is(':hidden');           // false
```

```js:jQueryを使わない例
// Element.matches() を使用する（ベンダープレフィックスにも対応させる）
if (!Element.prototype.matches) {
  Element.prototype.matches =
    Element.prototype.matchesSelector ||
    Element.prototype.webkitMatchesSelector ||
    Element.prototype.msMatchesSelector;
}

var getStyle = window.getComputedStyle;

var ppp = document.querySelector('#ppp');

ppp.matches('input');             // true
ppp.matches('div');               // false
ppp.matches('.pppLive');          // true
ppp.matches('.ppp');              // false
ppp.matches('[type="radio"]');    // false
ppp.matches('[name="penguin"]');  // true
ppp.matches(':disabled');         // true
ppp.matches(':checked');          // false

// jQuery で使える特殊セレクタは使用できないので、別の方法を使う
/// :visible の代替
getStyle(ppp).display !== 'none';  // true
/// :hidden の代替
getStyle(ppp).display === 'none';  // false
```

##.val()

フォーム系要素の値を取得・変更します。

以下のようなフォーム要素があったとします。

```html:Before
<input id="ppp" type="text" name="penguins" value="ぺぱぷらいぶ！">
```

```js:jQueryを使った例
var $ppp = $('#ppp');

// 値を取得
$ppp.val();  // "ぺぱぷらいぶ！"

// 値を変更
$ppp.val('Penguins Performance Project');
```

```js:jQueryを使わない例
var ppp = document.querySelector('#ppp');

// 値を取得
ppp.value;  // "ぺぱぷらいぶ！"

// 値を変更
ppp.value = 'Penguins Performance Project';
```

##.width(), .height(), .innerWidth(), .innerHeight(), .outerWidth(), .outerHeight()

要素の幅や高さを取得・変更します。
このメソッドの注意点として、**HTML上での見た目の幅・高さと同じ値とは限らない**という事です。
要素の状態やメソッドによってさまざまな解釈の違いがあります。

以下のようなCSSが適用されている `#contentBox` と `#borderBox` いう要素があったとします。

```css:CSS
#contentBox,
#borderBox {
  width: 100px;
  height: 50px;
  padding: 10px;
  margin: 10px;
  padding: 10px;
  border: 5px solid #000;
}
#borderBox {
  box-sizing: border-box;
}
```

HTML上の見た目では、`#contentBox` は幅が `130px`、高さが `80px`、`#borderBox` は幅が `100px`、高さが `50px` な要素になっています。

```js:jQueryを使った例
var
  $contentBox = $('#contentBox'),
  $borderBox = $('#borderBox');

/* 幅・高さの取得 */
// .width() / .height()
// ブラウザがCSSで解釈している値
$contentBox.width();   // 100
$contentBox.height();  // 50

$borderBox.width();    // 100
$borderBox.height();   // 50

// .innerWidth() / .innerHeight()
// ボーダーを含めない値
$contentBox.innerWidth();   // 120
$contentBox.innerHeight();  // 70

$borderBox.innerWidth();    // 90
$borderBox.innerHeight();   // 40

// .outerWidth() / .outerHeight()
// ボーダーを含めた値
$contentBox.outerWidth();   // 130
$contentBox.outerHeight();  // 80

$borderBox.outerWidth();    // 100
$borderBox.outerHeight();   // 50

/* 幅・高さの指定 */
// .width() / .height()
// ブラウザがCSSで解釈している値
$contentBox.width(70);   // HTML上の見た目では 100px になる
$contentBox.height(20);  // HTML上の見た目では 50px になる

$borderBox.width(70);    // HTML上の見た目では 70px になる
$borderBox.height(20);   // HTML上の見た目では 20px になる

// .innerWidth() / .innerHeight()
// ボーダーを含めない値
$contentBox.innerWidth(70);   // HTML上の見た目では 80px になる
$contentBox.innerHeight(20);  // HTML上の見た目では 30px になる

$borderBox.innerWidth(70);    // HTML上の見た目では 80px になる
$borderBox.innerHeight(20);   // HTML上の見た目では 30px になる

// .outerWidth() / .outerHeight()
// ボーダーを含めた値
$contentBox.outerWidth(70);   // HTML上の見た目では 70px になる
$contentBox.outerHeight(20);  // HTML上の見た目では 20px になる

$borderBox.outerWidth(70);    // HTML上の見た目では 70px になる
$borderBox.outerHeight(20);   // HTML上の見た目では 20px になる
```

```js:jQueryを使わない例
var getStyle = window.getComputedStyle;
function getStyleValue(element, prop) {
  return parseFloat(getStyle(element).getPropertyValue(prop)) || 0;
}

var
  contentBox = document.querySelector('#contentBox'),
  borderBox = document.querySelector('#borderBox');

/* 幅・高さの取得 */
//.width() / .height() の代替処理
getStyleValue(contentBox, 'width');   // 100
getStyleValue(contentBox, 'height');  // 50

getStyleValue(borderBox, 'width');    // 100
getStyleValue(borderBox, 'height');   // 50

// .innerWidth() / .innerHeight() の代替処理
function innerWidth(element) {
  var borderWidth = getStyleValue(element, 'border-left-width') + getStyleValue(element, 'border-right-width');
  return element.offsetWidth - borderWidth;
}
function innerHeight(element) {
  var borderWidth = getStyleValue(element, 'border-top-width') + getStyleValue(element, 'border-bottom-width');
  return element.offsetHeight - borderWidth;
}

innerWidth(contentBox);   // 120
innerHeight(contentBox);  // 70

innerWidth(borderBox);    // 90
innerHeight(borderBox);   // 40

// .outerWidth() / .outerHeight() の代替処理
contentBox.offsetWidth;   // 130
contentBox.offsetHeight;  // 80

borderBox.offsetWidth;    // 100
borderBox.offsetHeight;   // 50

/* 幅・高さの指定 */
//.width() / .height() の代替処理
contentBox.style.width = '70px';   // HTML上の見た目では 100px になる
contentBox.style.height = '20px';  // HTML上の見た目では 50px になる

borderBox.style.width = '70px';    // HTML上の見た目では 70px になる
borderBox.style.height = '20px';   // HTML上の見た目では 20px になる

// .innerWidth() / .innerHeight() の代替処理
function setInnerWidth(element, value) {
  var section;
  if (getStyle(element).boxSizing === 'border-box') {
    section = getStyleValue(element, 'border-left-width') + getStyleValue(element, 'border-right-width');
    value = value + section;
  } else {
    section = getStyleValue(element, 'padding-left') + getStyleValue(element, 'padding-right');
    value = value - section;
  }
  element.style.width = value + 'px';
}
function setInnerHeight(element, value) {
  var section;
  if (getStyle(element).boxSizing === 'border-box') {
    section = getStyleValue(element, 'border-top-width') + getStyleValue(element, 'border-bottom-width');
    value = value + section;
  } else {
    section = getStyleValue(element, 'padding-top') + getStyleValue(element, 'padding-bottom');
    value = value - section;
  }
  element.style.height = value + 'px';
}

setInnerWidth(contentBox, 70);   // HTML上の見た目では 80px になる
setInnerHeight(contentBox, 20);  // HTML上の見た目では 30px になる

setInnerWidth(borderBox, 70);    // HTML上の見た目では 80px になる
setInnerHeight(borderBox, 20);   // HTML上の見た目では 30px になる

// .outerWidth() / .outerHeight() の代替処理
function setOuterWidth(element, value) {
  var borderWidth, padding;
  if (getStyle(element).boxSizing !== 'border-box') {
    borderWidth = getStyleValue(element, 'border-left-width') + getStyleValue(element, 'border-right-width');
    padding = getStyleValue(element, 'padding-left') + getStyleValue(element, 'padding-right');
    value = value - borderWidth - padding;
  }
  element.style.width = value + 'px';
}
function setOuterHeight(element, value) {
  var borderWidth, padding;
  if (getStyle(element).boxSizing !== 'border-box') {
    borderWidth = getStyleValue(element, 'border-top-width') + getStyleValue(element, 'border-bottom-width');
    padding = getStyleValue(element, 'padding-top') + getStyleValue(element, 'padding-bottom');
    value = value - borderWidth - padding;
  }
  element.style.height = value + 'px';
}

setOuterWidth(contentBox, 70);   // HTML上の見た目では 70px になる
setOuterHeight(contentBox, 20);  // HTML上の見た目では 20px になる

setOuterWidth(borderBox, 70);    // HTML上の見た目では 70px になる
setOuterHeight(borderBox, 20);   // HTML上の見た目では 20px になる
```

CSSの `box-sizing` を考慮しないといけないので非常にややこしい処理を行っています。めんどくさい……

##.offset(), .position()

ドキュメントルートからみた要素の座標（絶対座標）、親要素から見た要素の座標を取得します。

```js:jQueryを使った例
var $absoluteBlock = $('#absoluteBlock');

// ドキュメントルートからみた #absoluteBlock の座標の取得
var offset = $absoluteBlock.offset();
offset.left;  // X座標
offset.top;   // Y座標

// 親要素から見た #absoluteBlock の座標の取得
var position = $absoluteBlock.position();
position.left;  // X座標
position.top;   // Y座標
```

```js:jQueryを使わない例
var absoluteBlock = document.querySelector('#absoluteBlock');

// ドキュメントルートからみた #absoluteBlock の座標の取得
function getOffset(element) {
  var rect = element.getClientRects().length > 0 ? element.getBoundingClientRect() : {top: 0, left: 0};

  return {
    top: rect.top + window.pageYOffset - document.documentElement.clientTop,
    left: rect.left + window.pageXOffset - document.documentElement.clientLeft,
  };
}

var offset = getOffset(absoluteBlock);
offset.left;  // X座標
offset.top;   // Y座標

// 親要素から見た #absoluteBlock の座標の取得
function getPosition(element) {
  var
    offset, offsetParent,
    parent = {top: 0, left: 0},
    style = window.getComputedStyle(element);

  if (style.position === 'fixed') {
    offset = element.getBoundingClientRect();
  } else {
    offset = getOffset(element);
    offsetParent = element.offsetParent || document.documentElement;

    if (offsetParent.nodeName !== 'HTML') {
      parent = getOffset(offsetParent);
    }

    parent.top += parseFloat(style.borderTopWidth);
    parent.left += parseFloat(style.borderLeftWidth);
  }

  return {
    top: offset.top - parent.top - parseFloat(style.marginTop),
    left: offset.left - parent.left - parseFloat(style.marginLeft),
  };
}

var position = getPosition(absoluteBlock);
position.left;  // X座標
position.top;   // Y座標
```

これはちょっとめんどくさいかも……

##.scrollLeft(), .scrollTop()

スクロール位置の取得・設定をします。

```js:jQueryを使った例
// 現在のスクロール位置の取得
$(window).scrollLeft();  // 例えば 0
$(window).scrollTop();   // 例えば 500

// スクロール位置の指定
$(window).scrollLeft(100);  // 左から100pxの位置に移動（横スクロールが有効な場合）
$(window).scrollTop(200);   // 上から200pxの位置に移動（縦スクロールが有効な場合）
```

```js:jQueryを使わない例
// 現在のスクロール位置の取得
window.pageXOffset;  // 例えば 0
window.pageYOffset;  // 例えば 500

// スクロール位置の指定
window.scrollTo(100, 200);  // 左から100px、上から200pxの位置に移動
```

##.show(), .hide()

要素を表示・非表示にします。

```js:jQueryを使った例
// #hiddenContent を表示
$('#hiddenContent').show();

// #visibleContent を非表示
$('#visibleContent').hide();
```

```js:jQueryを使わない例
/* 表示するときすべて display: block; でいい場合 */
// #hiddenContent を表示
document.querySelector('#hiddenContent').style.display = 'block';

// #visibleContent を非表示
document.querySelector('#visibleContent').style.display = 'none';

/* 表示するときに要素の display の初期値にしたい場合 */
var defaultDisplay = {DIV: 'block', SPAN: 'inline'};
function getDefaultDisplay(element) {
  var nodeName = element.nodeName;

  if (!defaultDisplay[nodeName]) {
    element = document.body.appendChild(document.createElement(nodeName));
    defaultDisplay[nodeName] = window.getComputedStyle(element).display;
    document.body.removeChild(element);
  }

  return defaultDisplay[nodeName];
}

// #hiddenContent を表示
var hiddenContent = document.querySelector('#hiddenContent');
hiddenContent.style.display = getDefaultDisplay(hiddenContent);
```

##.on(), .off(), .click()等

要素のイベントを追加・削除します。

```js:jQueryを使った例
var $clickHere = $('#clickHere');

// #clickHere にクリックイベントを追加
$clickHere.on('click', function (ev) {
  // do something
});
// または
// $clickHere.click(function (ev) {
//   // do something
// });

// #clickHere からクリックイベントの削除
$clickHere.off('click');
```

```js:jQueryを使わない例
var clickHere = document.querySelector('#clickHere');

// クリックイベント関数
function clickEvent(ev) {
  // do something
};

// #clickHere にクリックイベントを追加
clickHere.addEventListener('click', clickEvent);

// #clickHere からクリックイベントの削除
clickHere.removeEventListener('click', clickEvent);
```

##.one()

イベントを一度だけ実行します

```js:jQueryを使った例
// #clickHere に一度だけ有効なクリックイベントを追加
$('#clickHere').one('click', function (ev) {
  // do something
});
```

```js:jQueryを使わない例
var clickHere = document.querySelector('#clickHere');

// #clickHere に一度だけ有効なクリックイベントを追加
clickHere.addEventListener('click', function clickEvent(ev) {
  clickHere.removeEventListener('click', clickEvent);

  // do something
});
```

##.hover()

マウスのホバーイベントを追加します。

```js:jQueryを使った例
// #hoverHere にホバーイベントを追加
$('#hoverHere').hover(function (ev) {
  // mouseenter
  // do something
}, function (ev) {
  // mouseleave
  // do something
});
```

```js:jQueryを使わない例
var clickHere = document.querySelector('#clickHere');

// #hoverHere にホバーイベントを追加
clickHere.addEventListener('mouseenter', function (ev) {
  // do something
});
clickHere.addEventListener('mouseleave', function (ev) {
  // do something
});
```

`mouseover` と `mouseout` ではないんですね。

##.toArray()

要素リストを純粋な配列に変換します。

```js:jQueryを使った例
// div要素の取得
var $div = $('div');

$.isArray($div);  // false

// 配列に変換する
$div = $div.toArray();

$.isArray($div);  // true
```

```js:jQueryを使わない例
// div要素の取得
var div = document.querySelectorAll('div');

Array.isArray(div);  // false

// 配列に変換する
div = Array.prototype.slice.call(div);

Array.isArray(div);  // true
```

ECMAScript 2015 なら `Array.from()` が使用できます。

```js:jQueryを使わない例
// div要素の取得
let div = document.querySelectorAll('div');

Array.isArray(div);  // false

// 配列に変換する
div = Array.from(div);

Array.isArray(div);  // true
```

#アニメーション

jQueryはアニメーションが簡単に設定できて便利ですが、CSSでもアニメーションを行えるのでそれで代わりに書いてみようという感じです。

##フェードイン・フェードアウト

ボタンをクリックすると画像がフェードイン・フェードアウトを繰り返す動作をやってみます。

```html:HTML
<div id="fadeEffectTarget"><img src="./serval-chan.jpg" width="100" height="200" alt="サーバルちゃん"></div>
<button id="fadeEffect">Click Here</button>
```

###jQueryを使った例

```js:JavaScript
$('#fadeEffect').click(function () {
  $('#fadeEffectTarget').fadeToggle(300);
});
```

###jQueryを使わない例

```css:CSS
#fadeEffectTarget {
  transition: opacity 300ms ease;
}
.fadeOut {
  opacity: 0;
}
```

####ただ単にフェードするアニメーションの場合

```js:JavaScript
var target = document.querySelector('#fadeEffectTarget');

document.querySelector('#fadeEffect').addEventListener('click', function () {
  target.classList.toggle('fadeOut');
});
```

####フェードアウト時に display: none; にする必要がある場合

```js:JavaScript
var target = document.querySelector('#fadeEffectTarget');

document.querySelector('#fadeEffect').addEventListener('click', function () {
  var transitionEnd = function () {
    target.removeEventListener('transitionend', transitionEnd);
    target.style.display = 'none';
  };

  if (target.classList.contains('fadeOut')) {
    target.removeEventListener('transitionend', transitionEnd);
    target.style.display = 'block';
    setTimeout(function () {
      target.classList.remove('fadeOut');
    });
  } else {
    target.classList.add('fadeOut');
    target.addEventListener('transitionend', transitionEnd);
  }
});
```

他のアニメーションに関しては後日追加する、かも？

#おわりに

DOM関係の操作ってやっぱり面倒ですね。jQueryはやはり便利……
しかし、こういった事を行っていくことで、更にJavaScriptでのDOM関係の操作について理解が深まるのではないかと思います。