読者です 読者をやめる 読者になる 読者になる

コンパイラかく語りき

文系新卒プログラマーのメモ

JSライブラリ「Underscore.js」を読んでJavaScript中級者になる! ~void, call, apply~

どうも!chuckです。

引き続きUnderscore.jsのコードを読んでいきます。

 

chuckwebtips.hatenablog.com

 

ちなみに、現在100行まで読んだようです。ただし全部で1600行あるので先は長いですね…。

 

 

バージョン情報のセット

まず見るのはこの記述。

f:id:chuck0523:20150909215557p:plain

すごくシンプルな処理ですが、アンダースコアオブジェクトにバージョン情報をセットしています。

ファイル内検索したところ、特に使っている様子は無かったです。

 

最適化コールバック関数

急に来ました。すごく難しそうな関数。

f:id:chuck0523:20150909215922p:plain

 

まず、コメントを翻訳してみます。

Internal function that returns an efficient (for current engines) version of the passed-in callback, to be repeatedly applied in other Underscore functions.

渡されたコーツバックの(現在のエンジンでの)効率的なやつを返す内部関数 。他の関数でも繰り返し適用される。

 

ふむ、わからんw

 

分解してみる

まず引数を見てみます。

f:id:chuck0523:20150909220229p:plain

引数は3つ。名前から察するに「関数、コンテキスト、引数の数」っぽいですね。

 

処理を見ていきます。

まずこれ。

f:id:chuck0523:20150909220357p:plain

contextが、void 0 だったら…???謎です。

voidってあれですよね。Javaで言うと返り値がないやつ。JavaScriptにもあったんですね!

 

ググった。

f:id:chuck0523:20150909220531p:plain

ん?なんか不穏ですねw

 

developer.mozilla.org

 

解説はこんな感じ。

void 演算子は与えられた式 (expression) を評価し、undefined を返します。

 

用途的には、

この演算子は、「戻り値が undefined であってほしい場所に、それ以外の戻り値を持つ式を挿入したい場合」に有用です。

 

とのこと。

 

解説の下の方にこんな文章が。

void 演算子は単にプリミティブ値 undefined を得る目的でしばしば使われ、一般的に "void(0)" と書かれます(これは "void 0" と等価です)。

要は、undefinedをリテラルで書かない場合に使うってこと?

 

使ってみる!

testという変数に'test'をセット。その後、void(0)で上書きしてみます。

f:id:chuck0523:20150909221907p:plain

 

おっ。

f:id:chuck0523:20150909221941p:plain

 たしかに、undefinedに上書きされています。

 

話をUnderscore.jsに戻します。

つまり、この条件文は、引数のcontextがundefinedだったときにtrueになるんですね!

f:id:chuck0523:20150909222016p:plain

 そして、引数で渡された関数をそのまま返してますね。

 

次にこの箇所。

f:id:chuck0523:20150909222310p:plain

いやあ、なんというか、やばいですね…w

 

まずswitch文の()の中に三項演算子を使っているの、初めて見ました。

その箇所をズーム。

f:id:chuck0523:20150909222541p:plain

argCount == null は、あえて等値演算子(==)を使っていますね。たぶん。

 

「引数にargCountが渡されていなかったら」という処理をしたいと思うんですけど、その場合argCountはundefinedになります。なので、同値演算子(===)を使うとnullとイコールになりません。

f:id:chuck0523:20150909222927p:plain

 

でも、ここでなぜ void(0) を使わなかったのか…。うーむ。

 

いづれにせよ、argCountがなかったらデフォルトで3に設定しているわけですね。

それ以外の場合はargsCountが1か4に設定されるようです。

f:id:chuck0523:20150909222541p:plain

 

では、条件文で振り分けられたあとの、swtich文の中身を見ていきます。

argsCountが1だった場合の処理。

f:id:chuck0523:20150909223735p:plain

valueという引数を取ってfunc.call(context, value)をreturn する、そんな関数をreturnします。…ややこしいですね。

 

というか、callについて、実はまだよくわかっていません…。

調べた。

developer.mozilla.org

 

概要はこんな感じ。

this の値と、個々にあたえた引数をわたして、関数を呼び出します。

 

f:id:chuck0523:20150909224453p:plain

 ここでthisArgはこんな役割を持つそう。

呼び出し先関数 fun の中で this パラメータとして使用される値です。 実際にこの値が関数の中で this の値として使用されるとは限りません: もし、関数が non-strict mode のコードで、null か undefined が指定された場合は this の値は global object になります。 また、プリミティブ値はボクシングされます。

ちなみにarg1, arg2... は普通の引数。

 

つまり、contextを関数のthisにセットして、それをreturnしているのがこの処理ですね。

f:id:chuck0523:20150909223735p:plain

 

あれ、他の2つの場合も一緒かも。

f:id:chuck0523:20150909224929p:plain

引数の数が違うだけで、contextをthisにセットしていますね!

 

そして、これが最後の処理。

if文にもswitch文にも引っかからなかった場合は、この処理に飛ぶようです。

f:id:chuck0523:20150909225052p:plain

出ました。apply。これも分かったようで分かってないかも…。

 

また調べた。

developer.mozilla.org

thisの値をセットできる点では、まあ同じかな。

 

callとapplyの違いについては、これがわかりやすかったかも!

taiju.hatenablog.com

 

qiita.com

 

なんとなく全体像をつかめた

関数の中身を分解することで、なんとなく全体像がつかめました。

要はcontextが鍵になっていますね。まずif文でcontextがあるか判定して、あればswitch文で分岐させて、contextをthisにセットしています。

 

だから何?

僕はまだJavaScript中級者未満なので、任意の値をthisにセットするメリットがぱっと浮かびません。

あれですかね?関数の呼び出し方によっては、thisがグローバルオブジェクトを指してしまうので、thisをthatやselfとして確保する必要があるじゃないですか?

そういうことを考えずに済むのかな???

 

まとめ

ふわーっとですが、処理の流れを追うことが出来ました。

今回はcontext, void, call, applyなど、いかにもJavaScript中級者っぽいワードが出ましたね!call, applyについてはまだ完全に理解したわけではないので、また別で整理できればと思います。