JavaScriptライブラリの気になる実装をどうやって見ていくか
はじめに
毎日新しいJavaScriptライブラリが登場していると思いますが、それらがどういう実装になっているかを知ることはライブラリを使う以上に大事かもしれません。
ソースを全部読めば分かるかもしれませんが、それをやるには時間が足りません。
JavaScriptに限った話では無いですが、今回はJavaScriptを例に”特定の機能はどうやってるんだろ?”という事を調べる方法についてです。
探す前にドキュメントに載ってないかを見るのが手間がなくて一番よいですが、書いてない場合は実装を見ます。
Vue.js
今回はVue.jsというAngularJSやKnockoutのようなViewとModelのデータバインディグを行うライブラリを例に、データバインディグはどうやっているのかを2つの方法で調べてみたいと思います。
コードをステップで見ていく
これはよく見る方法で皆さんもやったことがあると思います。
見たい挙動(今回はモデルへのバインディグ)のサンプルコードを書いて、
そこに対してブレークポイントを貼り step in しながら目的の実装を探すという単純な方法です。
トップページにあるサンプルコードを見ても分かるように、new Vue({ /*モデル*/ })
となってるので、Vueコンストラクタの実装を見ていけばいいことがわかります。
var demo = new Vue({// < - breakpoint
el: '#demo',
data: {
message: 'Hello Vue.js!'
}
})
</span>
サンプルコードを書いて new Vue
の部分にブレークポイントを貼るだけで準備完了です。
後は、デバッガーのステップ実行しながら、怪しい関数等を見ていくだけです(今回ならObserveとかbindingとかの用語を見ていけば多分見つかるはずです)
以下は実際に見ていった動画です
勘であてる
もう一つ短時間で探す方法として、その機能(今回はデータバインディグ)に使われそうなメソッドや名前で検索してしまう方法です。
今回はデータバインディグがキーワードです。
また、Browser Supportを見るとES5サポートしている事が前提となってることがわかります。
Vue.js supports most ECMAScript 5 compliant browsers, essentially IE9+. IE8 and below are not supported.
ここで、ピンと来る人もいると思いますが他のところもチェックすると、サンプルコードを見てもknockout.jsのように値の変更を監視するためにラッパーをかぶせたりはしていないように見えます。
knockoutの場合は監視したいプロパティに ko.observable(value)
のようなラップが必要になります。
この情報から推測するとJavaScriptネイティブのgetter/setterを使ってるんじゃないかと気付きます。
getter/setterを設定(他にも方法はありますが)するObject.definePropertyはES5からサポートされているので、ES5をサポートしてないブラウザはサポート外になってるんじゃないかという感じですね。
探すポイントは推測できたので実際に検索してみます。
(こっから先、普通に文字列検索してもいいと思うので若干蛇足気味です)
普通にgrep的な検索でもいいですが、JavaScriptを例にしたのでgraspを使ってみます。(多分このケースだと普通に文字列検索した方が楽です…)
graspは単純な文字列検索ではなくて、JavaScriptの構文を元に検索/置換が出来るコマンドラインツールです。
以下でも軽く紹介してるので見てみるといいかもしれません。
$ npm install -g grasp
でインストールしておきます。
Object.definePropertyを呼び出し箇所を検索
Object.defineProperty(obj, prop, descriptor)
のような構文なので、上記のように呼び出してる場所を検索したいと思います。
Object.defineProperty(obj, prop, descriptor)
に該当するものを検索する場合、
graspでは以下のように書くことが出来ます。
grasp -e 'Object.defineProperty(__,__,__)' src/*
一つづつ見ていくと、
- graspコマンドで
src/*
以下のファイルを検索しています -e
は Example Queryを使うというオプションです。- graspはExample QueryとSelector Queryの2つの方法で検索が出来ます
- ワイルドカード的なものとCSSセレクタ的なもので検索する方法です
'Object.defineProperty(__,__,__)'
は検索したいコードです__
というのが引数の数(3つ)あることがわかります。__
はワイルドカードの事を示しています- 正規表現なら
'Object.defineProperty(.*?,.*?,.*?)'
みたいな感じ? - 正規表現と違って、ホワイトスペースや改行等余計な事を意識しなくても書くことが出来ます。
その結果を見ると幾つか使ってる箇所がわかります。
後は、見つけた場所を実際に見ていくといった感じです。
Object.definePropertyのaliasを検索する
今回は直接 Object.defineProperty
を使っていたので問題無いですが、
Object.defineProperty
は長いのでライブラリの内部では以下のようなエイリアスを貼って使っているかもしれません。
var def = Object.defineProperty;
“Object.defineProperty” という文字列を検索すれば、見つけることも出来ますが、graspではもっと具体的に、”varである変数にObject.defineProperty
を代入している所” というのも検索出来ます。
正規表現でも出来そうに見えますが、以下のようなコードだと結構難易度が上がります。
var slice = Array.slice,
def = // for getter/setter
Object.defineProperty;
graspだと、以下のようにして検索することが出来ます。
grasp -e '__[init=Object.defineProperty]' test.js
結果を見るとちゃんと該当する部分を検索出来てる事がわかります。
検索できたので、どういう風に検索されているかを見ていきます(–debugオプションとかもあるのでそちらも見るといいかもしれないですね)
-e
や__
は先ほど同じ意味で、Example Queryとワイルドカードです
__[init=Object.defineProperty]
というのは、CSSセレクタをイメージすると分かりやすいです。
要素は__
なので何でもよいですが、ここでいう要素はJavaScript Syntax | Grasp – JavaScript structural search, replace, and refactorで説明されているJavaScript ASTの要素の事を言っています。
var a;
のような変数宣言は、 VariableDeclarator という要素(var-dec)に該当します。(上記の例はワイルドカードがこれに該当してる)
そしてVariableDeclaratorというのは init
というプロパティ(属性)を持っていて、この init
の値が Object.defineProperty
にマッチするものを検索しています。
(init
の値というは簡単に言えば、 var a = 1; の 1の部分)
この辺はコードをパースした結果を見比べて見るといいかもしれません。
graspはSelector QueryというCSSセレクタ的なものもあるので、こちらを使った場合は直感的では無いですが以下のように書くことが出来ます。
grasp -s 'var-dec[init=member[obj=#Object][prop=(#defineProperty)]]' test.js
今回はES5サポートというキーワードを元に安全で効率も良いgetter/setterを使ってると推測して検索しましたが、
キーワードが絞れない場合は実際にステップ実行を見ていったほうが楽だと思います。
古いIEをサポートしてるなら他の方法が幾つかありそうでキーワードから考えるのは中々難しい。
例えば、Ractive.jsのようにArray modification · RactiveJS/Ractive Wikiハックを使ったり、AngularJSはDirty checkingというやり方をしている等やり方的に幾つかでてくると思うので、
ステップ実行やドキュメントから探したりした方が効率が良さそうです。
その他
今回紹介した方法以外にも、最近のライブラリならある程度モジュールでファイルが別れてるはずなので、ファイル名をヒントに探すとか、
GithubやStackOverFlowで検索するとかやり口はいくらでもあります。
今回ターゲットにしたVue.jsもCommonnJSで書かれていて、componentを使ってファイルをビルド出来るようにしてました。
(ビルド環境も面白くて、Gruntを使っている感じでしたが、内部でgulp pluginであるgulp-componentを使ったりしてた)
おわりに
この記事では、JavaScriptのライブラリの実装を見ていく2つの方法について書きました。
- デバッガーを使ってステップ実行をして中身を見ていく方法
- graspを使ってキーワードから探していく方法
JavaScriptでは公開されてるライブラリも含め、普通のウェブサイトでもソースコードが見られてので、実際に動いてるソースが探せば見つけやすい世界です。
Webkit/Chrome/Firefox(27〜)のDevToolsではJavaScriptの整形表示機能もあったりします。
ソースコードから学べることも多いので、興味があるものは色々読んでみるといいかもしれません。
お知らせ欄
JavaScript Primerの書籍版がAmazonで購入できます。
JavaScriptに関する最新情報は週一でJSer.infoを更新しています。
GitHub Sponsorsでの支援を募集しています。