jQueryを使わない書き方 ajax, each, trigger, on/off, extend, deferred, animate, css編

昨年くらいから次世代JavaScript(ES2015 & 2016)やReactやAngularJSなどのフレームワークの普及により脱jQueryの動きが見られ始めました。そして2016年はさらに脱jQueryの動きが加速するのではないかと見ています。その最も大きな要因として1月12日に実行されたマイクロソフトによる旧IE(Internet Explorer 8, 9 ,10)のサポート終了が挙げられます。そんな訳でjQueryは便利ですが、特に使う必要もなくなってきているのが現状です。今回紹介するjQueryに頼りがちな処理をJSで書けるようにさえなれば、脱jQueryはすぐにでもできるのではないかと思っています。ぜひ参考にしてください。

はじめに

脱jQueryに関して以下のような記事が年末に投稿されました。

特にMOONGIFTさんの記事で紹介されているoneuijs/You-Dont-Need-jQueryはよくまとまっていて大変重宝します。日々内容のアップデートもされているようです。今回自分の記事では、You-Dont-Need-jQueryではまだ紹介されていなくて、かつよくjQueryで実装したくなる処理を、jQueryを使わずにどのように書くか紹介していきたいと思います。

ajax(非同期)

jQuery.ajax()メソッドは、非同期なHTTP通信を実装するためのメソッドで、jQueryで最も利用されるメソッドの一つです。以下はjQuery.ajax()メソッドを使ってgetリクエストを書いた例です。jQuery 1.8以降で推奨されている.done()メソッドと.fail()メソッドを使った書き方です。

// jQuery
$.ajax({
  url: "/serach?query=hoge&order=desc",
  type: "get"
}).done(function (data, textStatus, jqXHR) {
  console.log(data.statusText); // => "OK"
}).fail(function (jqXHR, textStatus, errorThrown) {
  console.log(errorThrown); // => Error Message
});
jQueryでの実装例

Nativeで書く

JavaScriptにはXMLHttpRequestというオブジェクトが用意されています。ご存知の方も多いと思いますが、昔ながらの書き方です。IE6ではこのXMLHttpRequestオブジェクトが使えず、ActiveXObjectオブジェクトというものを使うように、わざわざ書き分けが必要でした。この煩わしさを回避したいがために、jQuery.ajax()メソッドが普及したのだと思います。

//  Native
var request = new XMLHttpRequest();
request.open("get", "/serach?query=hoge&order=desc", true);
request.onload = function (event) {
  if (request.readyState === 4) {
    if (request.status === 200) {
      console.log(request.statusText); // => "OK"
    } else {
      console.log(request.statusText); // => Error Message
    }
  }
};
request.onerror = function (event) {
  console.log(event.type); // => "error"
};
request.send(null);
Nativeでの実装例

Native(Fetch API)で書く

WHATWGで仕様の策定が行なわれているFetch APIは、上記のXMLHttpRequestオブジェクトよりも取っ付きやすく、さらに高機能化が図られています。jQuery.ajax()メソッドのようにすっきり書くことができます。ただまだブラウザでの実装がそこまで進んでいないので、polyfillとの併用が必須となります。

// Native (HTML5 Fetch API)
fetch("/serach?query=hoge&order=desc", {
  method: "get"
}).then(function (response) {
  if (response.status === 200) {
    console.log(response.statusText); // => "OK"
  } else {
    console.log(response.statusText); // => Error Message
  }
}).catch(function (response) {
  console.log(response); // => "TypeError: ~"
});
Native(HTML5 Fetch API)での実装例

Fetch APIのpolyfillは以下となります。

SuperAgentで書く

browserifyやwebpackを使って開発する場合は、Ajax専用の軽量ライブラリであるSuperAgentが使えます。GitHubのスター数も6,000を超える程人気のライブラリとなっています。シンプルに書けて、とても扱いやすいライブラリです。

// SuperAgent
var request = require("superagent");

request
  .get("/search?query=hoge&order=desc")
  .end(function (err, res) {
    if (err || !res.ok) {
      console.log(err); // => "Error: ~" 
    } else {
      if (res.status === 200) {
        console.log(res.statusText); // => "OK"
      }
    }
  });
SuperAgentでの実装例

each(ループ)

.each()メソッドはループ処理を書く時によく使うjQueryのメソッドでしょう。マッチしたそれぞれの要素に対して、引数に指定した関数を実行するためのメソッドです。以下は.each()メソッドを使って、配列の繰り返し処理を書いた例です。

// jQuery
var array = [ "a", "b", "c" ];
$(array).each(function (i, val) {
  console.log(i); // => 0, 1, 2
  console.log(val); // => a, b, c
});
jQueryでの実装例

Native(forEach()メソッド)で書く

ES5でforEach()メソッドが策定されました。forEach()メソッドを使うと、引数のセットの仕方に違いがありますが、.each()メソッドとほぼ同じように書くことができます。ただ残念なことにforEachは「遅い」という話もあります。使う時は注意が必要です。

//  Native
var array = [ "a", "b", "c" ];
array.forEach(function (val, i, arr) {
  console.log(val); // => a, b, c
  console.log(i); // => 0, 1, 2
  console.log(arr); // => [ "a", "b", "c" ], [ "a", "b", "c" ], [ "a", "b", "c" ]
});
Native(.forEach())での実装例

extend(オブジェクトのマージ)

jQuery.extend()メソッドは、複数のオブジェクトをマージする時に使うメソッドです。jQueryプラグインを書く時にオプションのデフォルト値とユーザーが定義した値をマージする時によく使ったりしますね。以下はjQuery.extend()メソッドを使って、複数のオブジェクトをマージする処理を書いた例です。

// jQuery
var objA = { a: 1 };
var objB = { b: 2 };
var obj = $.extend({}, objA, objB);
console.log(obj); // => Object { a: 1, b: 2 }
jQueryでの実装例

Native(Object.assign()メソッド)で書く

ES2015でObject.assign()メソッドが策定されました。このObject.assign()メソッドを使うと、jQuery.extend()メソッドとほぼ同じ書き方で書くことができます。

//  Native (ES2015 Object.assign())
var objA = { a: 1 };
var objB = { b: 2 };
var obj = Object.assign({}, objA, objB);
console.log(obj); // => Object { a: 1, b: 2 }
Native(ES2015 Object.assign())での実装例

Object.assign()メソッドのpolyfillは以下となります。

trigger, on/off(カスタムイベント)

jQueryは、この.trigger()メソッドと.on()/.off()メソッドを使うことによって簡単にカスタムイベントを実装できるようになっています。これがかなり良くできていて、手軽に扱えるところが魅力です。以下は.trigger()メソッドと.on()/.off()メソッドを使って、カスタムイベントを書いた例です。

// jQuery
var $elem = $(".elem");

var listener = function () {
  console.log("Submit!!");
};

// イベント'submit'をバインド
$elem.on("submit", listener); // => "Submit!!"

// バインドしたイベント'submit'のリスナーを指定して削除
$elem.off("submit", listener);

// バインドしたイベント'submit'のリスナーを全て削除
$elem.off("submit");

// イベント発火
$elm.trigger("submit");
jQueryでの実装例

Nativeで書く

jQueryの.trigger()メソッドは、.dispatchEvent()メソッドで代替可能です。Eventオブジェクトでイベントを作り、.dispatchEvent()メソッドにセットすることで、イベントを発火させることができます。イベントのバインドは.addEventLister()メソッド、リスナーの削除は.removeEventListener()メソッドで行います。この2つのメソッドは、IE8以前のバージョンでは対応していませんでしたが、IE8のサポート終了により今後は気にせず使えるようになります。jQueryと比べると、若干実装に癖があります。

// Native
var elem = document.queryselector(".elem");

var listener = function () {
  console.log("Submit!!");
};

// イベント'submit'をバインド
elem.addEventListener("submit", listener, false); // => "Submit!!"

// バインドしたイベント'submit'のリスナーを指定して削除
elem.removeEventListener("submit", listener, false);

// イベント発火
elm.dispatchEvent(new Event("submit"));
Nativeでの実装例

Node.jsのEventEmitterで書く

browserifyやwebpackなどを使って開発する場合は、Node.jsのEventsモジュールのEventEmitterオブジェクトが使えます。使うまでの準備が若干煩わしいですが、使い勝手はjQueryに近くて、実装もしやすいと思います。

// Node.js (EventEmitter)
var EventEmitter = require("events").EventEmitter;

var listener = function () {
  console.log("Submit!!");
};

var event = new EventEmitter();

// イベント'submit'をバインド
event.on("submit", listerner); // => "Submit!!"

// バインドしたイベント'submit'のリスナーを指定して削除
event.removeListeners("submit", listener);

// バインドしたイベント'submit'のリスナーを全て削除
event.removeAllListeners("submit");

// イベント発火
event.emit("submit");
Node.js(EventEmitter)での実装例

Deferred(脱コールバック地獄)

jQuery.Deferredオブジェクトは、非同期処理をコールバック関数を使わずに書くためのオブジェクトです。非同期処理と非同期処理後の処理を別々に分けて書けるようになり、コールバック地獄に陥るのを防いでくれたり、コード全体の見通しを良くしてくれたりするので、大変重宝します。以下はjQuery.Deferredを使って非同期処理を書いた例です。

// jQuery
var asyncFunc = function () {
  var defer = new $.Deferred();
  setTimeout(function () {
    console.log("OK");
    defer.resolve("resolved");
  }, 5000);

  setTimeout(function () {
    console.log("NG");
    defer.reject("rejected");
  }, 5000);

  return defer.promise();
};

asyncFunc().done(function (data) {
  console.log(data); // => resolved
}).fail(function (data) {
  console.log(data); // => rejected
});
jQueryでの実装例

Native(ES2015のPromise)で書く

ES2015で待望のPromiseオブジェクトが策定されました。このPromiseオブジェクトを使うと、jQuery.Deferredとほぼ同じように書くことができます。インスタンス化する時の書き方に若干違いがあります。

//  Native (ES2015 Promise)
const asyncFunc = function () {
  var promise = new Promise(function (resolve, reject) {
    setTimeout(function () {
      console.log("OK");
      resolve("resolved");
    }, 5000);

    setTimeout(function () {
      console.log("NG");
      reject("rejected");
    }, 5000);
  });

  return promise;
};

asyncFunc().then(function (data) {
  console.log(data); // => resolved
}).catch(function (data) {
  console.log(data); // => rejected
});
Native(ES2015 Promise)での実装例

Promiseに関しては、以下のサイトがとても参考になります。

animate(アニメーション)

気軽にアニメーションを実装できる.animate()メソッドも、jQueryでよく使うメソッドでしょう。以下は.animate()メソッドを使って要素をアニメーションをつけてだんだん透明にしていく処理を書いた例です。

// jQuery
var $elem = $(".elem");

$elem.animate({
  opacity: 0
}, 500);
jQueryでの実装例

Native(HTML5のWeb Animations API)で書く

W3Cで仕様の策定が行なわれているWeb Animations APIですが、かなり高機能で自分は機能を把握しきれていませんが、一応代替が効きそうなので紹介します。jQueryの.animate()メソッドと基本スタイルは同じように書けますが、こちらでは.animate()メソッドにセットできるのは、配列かnullのみで、しかも配列には複数のkeyframeが必要のようです。

//  Native (HTML5 Web Animations API)
var elem = document.querySelector('.elem');

elem.animate([
  { opacity: 1 },
  { opacity: 0 }
], {
  fill: 'forwards',
  duration: 500
});
Native (HTML5 Web Animations API)での実装例

HTML5 Web Animations APIのpolyfillは以下となります。

css(スタイル)

.css()メソッドは、jQuery史上最も使われているメソッドと言っても過言じゃないくらいよく使われているメソッドじゃないでしょうか。特に説明はいらないと思います。以下は.css()メソッドを使って要素のスタイルを変更する処理を書いた例です。

// jQuery
var $button = $(".button");
$button.css({
  "border": "1px solid #333",
  "border-radius": "3px",
  "color": "#fff"
});
jQueryでの実装例

Native(ES2015 Template strings)で書く

JavaScriptではstyleプロパティでstyle属性に値をセットすることができますが、jQueryのcss()メソッドのように一度に複数の指定ができません。そこで、ES2015で策定されたTemplete Stringsを使った書き方をオススメします。以下のように、JavaScriptのsetAttribute()メソッドを使って、style属性の値をバッククォートで囲むことで、改行がそのまま認識され、jQueryのcss()メソッドと同じような感覚で書くことができるようになります。

//  Native (ES2015 Template strings)
var button = document.querySelector(".button");
button.setAttribute("style",
  `
  border: 1px solid #333;
  border-radius: 3px;
  color: #fff;
  `
);
Native(ES2015 Template strings)での実装例

注意点

今回紹介した方法は、ブラウザによって動いたり動かなかったりするものもあるため注意が必要です。それぞれのブラウザごとの実装状況については以下でお確かめください。

それから、requireして読み込んで使うようなものは、BrowserifyやWebpackなどを使ってブラウザで使えるようにしてください。

ES2015のものもブラウザで使えるようにするためにbabelでのコンパイルが必要です。

それからそれぞれの仕様については詳しく紹介できなかったので、記事内のリンク先のページにて確認していただければと思います。

まとめ

脱jQueryを促すような記事を書きましたが、個人的にはjQueryプラグインを書いたりもしているので、jQueryへの思い入れは意外と強かったりします。ただやはり最近では、だいぶjQueryを使う機会は減ってきていますし、今後はさらにそうなっていくのかなと思っています。今回の記事で紹介したように代替が可能になってきていますし、旧IEのサポートも終了しましたし、jQueryを使う理由がなくなってきているのは確かです。

自分は元々はprototype.js派で、jQueryを使い始めたのは2011年くらいでちょっと遅かったかもしれません。prototypeからjQueryに乗り換える時は結構大変だったのを覚えています。今は何不自由なく使えるようになっていますが、まだまだ理解していない部分も多々あるんだろうなと思っています。そんな状況で残念ではありますが、やはり使用頻度が減っていくはやむをえないですかね。

ただ、jQueryも昨年から色々動きがあって、jQuery FoundationとDojo Foundationの統合したり、タスクランナーであるGruntがjQuery Foundationに加入したり、そして今年はjQueryは10周年を迎えるということで、1/14にjQuery 3.0 betaがリリースされたりしました。いろいろと面白いことをしてくれたらいいいですね。その辺はしっかりと見守っていこうと思っています。

コメント一覧

  • 必須

コメント