アンケートご協力のお願いgihyo.jpでは,2010年度に向けて豪華プレゼントが当たる読者属性アンケートを実施しております。ご協力ください。

gihyo.jp » DEVELOPER STAGE » 特集 » prototype.jsを読み解く » 第3回 Prototypeライブラリ(640~931行目)

prototype.jsを読み解く

第3回 Prototypeライブラリ(640~931行目)

ソースの意図の探り方

第三回目です。

オープンソースの成果物を利用する際に,より理解を深めようとするとソースを追っていく必要がでてきます。その際,ソースの特定の箇所が,なぜそうなっているのかが理解できない部分に遭遇することもよくあります。

幸いなことに,多くのオープンソースの配布物はCVSやSubversionなどのバージョン管理システムで管理されており,その履歴が公開されています。

Prototypeライブラリは現在ではRuby on RailsのSubversionリポジトリ上で管理されており,この場合はRails Tracのリポジトリブラウザから辿っていくのがわかりやすくてお勧めです。

ライブラリを利用する際には単一のprototype.jsというファイルとなっていますが,リポジトリ上ではいくつかのファイルに分類されて管理されており,rakeコマンドで結合してリリースされています。

そこで,まずはバージョンの履歴をさかのぼり,コミットログを確認していく,という所からはじめます。Railsのリポジトリはログも丁寧に書かれており,関連するTrack Ticketの番号も明記されています。

では,今回はArray関連からです。

$A()関数

0640: var $A = Array.from = function(iterable) {
0641:   if (!iterable) return [];
0642:   if (iterable.toArray) {
0643:     return iterable.toArray();
0644:   } else {
0645:     var results = [];
0646:     for (var i = 0, length = iterable.length; i < length; i++)
0647:       results.push(iterable[i]);
0648:     return results;
0649:   }
0650: }
0651: 

640行目からは$A()関数です。同時にArray.form()というエイリアスも作られています。引数として渡されたオブジェクトを,できるだけ配列型にして返そうとします。

641行目では,渡されたものがそもそも偽として判断されるようなものには空配列を返しています。

次に,渡されたiterableオブジェクトがtoArrayプロパティを持っている場合には,それをメソッドとみなして呼び出し,返り値を返します。EnumerableをmixinしているクラスのオブジェクトはここでtoArray()が使われます。

それ以外の場合,645行目からfor文で中身をひとつずつ取り出してresultsにpush()する,という形で取り出していきます。通常の配列はここの処理となりますが,配列に数字プロパティ以外のプロパティ値がセットされていたとしても,ここではコピーされません。

0652: if (Prototype.Browser.WebKit) {
0653:   $A = Array.from = function(iterable) {
0654:     if (!iterable) return [];
0655:     if (!(typeof iterable == 'function' && iterable == '[object NodeList]') &&
0656:       iterable.toArray) {
0657:       return iterable.toArray();
0658:     } else {
0659:       var results = [];
0660:       for (var i = 0, length = iterable.length; i < length; i++)
0661:         results.push(iterable[i]);
0662:       return results;
0663:     }
0664:   }
0665: }
0666: 

652行目からは,$A()関数のApple WebKit対策です。

中身はほぼ同じですが,toArray()を使う条件が異なります。Safariではテキストノードを含むノードリストに対して素の$A()を使うとクラッシュする,という報告があり,条件を満たすオブジェクトの場合はtoArray()を使わずにforループでまわす,としています。

Array オブジェクトへの拡張

0667: Object.extend(Array.prototype, Enumerable);
0668: 

Arrayの拡張をするのに,まずEnumerableで定義されているメソッドをまるごとArray.prototypeにmixinします。

0669: if (!Array.prototype._reverse)
0670:   Array.prototype._reverse = Array.prototype.reverse;
0671: 

後でArray.prototype.reverse()メソッドを上書きしてしまうので,ここでオリジナルの関数オブジェクトを_reverseに保存しておきます。

0672: Object.extend(Array.prototype, {
0673:   _each: function(iterator) {
0674:     for (var i = 0, length = this.length; i < length; i++)
0675:       iterator(this[i]);
0676:   },
0677: 

mixinしたEnumerable.each()から参照される_each()メソッドです。ここでは単純な配列なので,for文を使って0から順に辿ってiterator関数を呼び出す実装となっています。

0678:   clear: function() {
0679:     this.length = 0;
0680:     return this;
0681:   },
0682: 

678行目からはclear()メソッドです。配列の場合はlengthプロパティに0をセットするだけで要素をクリアできるので,そのようにしています。

0683:   first: function() {
0684:     return this[0];
0685:   },
0686: 
0687:   last: function() {
0688:     return this[this.length - 1];
0689:   },
0690: 

683行目からはfirst()メソッドです。配列では単にthis[0]と先頭の要素を返しています。

687行目からのlast()メソッドも簡単で,this[this.length - 1]が最後の要素なのでそれを返します。

0691:   compact: function() {
0692:     return this.select(function(value) {
0693:       return value != null;
0694:     });
0695:   },
0696: 

691行目からはcompact()メソッドです。nullかundefinedな要素を取り除いた配列を返します。

undefinedを!=でnullと比較すると真になるため(undefinedがnullに暗黙的に型変換される),select()に渡す関数内の判別式はvalue != nullという形となります。

0697:   flatten: function() {
0698:     return this.inject([], function(array, value) {
0699:       return array.concat(value && value.constructor == Array ?
0700:         value.flatten() : [value]);
0701:     });
0702:   },
0703: 

697行目からはflatten()メソッドです。多層構造の配列をフラットな一次元配列に変換します。階層構造に対応するために,再帰的にflatten()を呼び出すようになっています。

689行目で,空配列を初期値としてinject()を呼び出します。呼び出される関数オブジェクトの中では,Arrayの要素値が真で,かつconstructorプロパティがArrayなら再帰的にflatten()を呼び出してその返り値を,そうでなければその値を配列にしてarray.concat()に渡しています。

new式で生成されたオブジェクトは,prototype.constructorとして生成に用いられた関数オブジェクトを持ちます。ここでは,valueとして渡されたオブジェクトのconstructorプロパティが,Arrayのコンストラクタ関数と等価であるかどうかを見ています。

著者プロフィール

栗山淳(くりやまじゅん)

S2ファクトリー株式会社株式会社イメージソース所属。
本業はWeb制作会社の裏方。得意分野はFreeBSDやPerlのはずだが,必要に迫られるとHTML/CSSやJavaScriptも書く。

コメント

コメントの記入

パスサポ

多数の情報処理技術者試験対策書籍の発行実績を誇る技術評論社がお届けする,資格試験合格サイト「めざせ! 情報処理試験 パスサポ」が開設されました。

ピックアップ

サクセスストーリーに続く,快適サーバー運用管理のヒント!

データの増大,煩雑な管理,システムダウン,セキュリティなど,迫りくる課題からシステム管理者の負担を軽くするポイントを解説します。

gihyo.jp インフラエンジニア情報局

ネットワークやITにかかわるあらゆる業種で必要とされるインフラエンジニアに向けた技術情報や心構え,その魅力について多角的に紹介。

テストエンジニア ステーション

いま,ITに関わるあらゆる開発業務で注目されつつあるテスト系エンジニアをターゲットにしたコンテンツサイトを展開します。

一行クイックアンケート

gihyo.jpで取り上げてほしいネタは?

※検索はページ右上の検索ボックスをご利用ください。

その他の連載

読むウェブ ~本とインタラクション

ディスプレイで読む活字とそのインタラクション(interaction:相互作用)について,最新Webを紹介しながら読み解いていく。

いま,見ておきたいウェブサイト

この連載では,国内外の最新のウェブサイトを隔週更新で取り上げ,これら最新サイトの特徴や素晴らしい部分を,さまざまな角度から解説していきます。

Windows phoneアプリケーション開発入門

Windows Marcketplace for Mobileがサービス開始され,作成したアプリケーションを個人でも世界をターゲットに公開できる環境が整ってきました。これを機にWindows phoneアプリケーションの開発をしてみませんか?

ここは知っておくべき!Windows Server 2008技術TIPS

5年ぶりのサーバOSとなったWindows Server 2008が出荷されて早2年。2009年にはR2が出荷され,再び注目を集めています。発売前から実施したトレーニングによって感じた,インフラエンジニアの方々に知っておいていただきたい機能を中心にご紹介します。

キーパーソンが見るWeb業界

本連載はWeb Site Expert/gihyo.jpとの連動企画です。阿部淳也, 長谷川敦士, 森田雄のお三方による,Web業界をテーマにした座談会です。

きたみりゅうじの聞かせて珍プレー

ソフトウェア開発の現場で体験したトホホな失敗,思わずうなる珍プレーをきたみりゅうじ氏が四コママンガで紹介。みなさんからの投稿もお待ちしてます!

ActionScript 3.0で始めるオブジェクト指向スクリプティング

野中文雄氏が,簡単なスクリプトは書いたことがあるという初級者を対象に,ActionScript 3.0の基本からクラス定義までを解説します。

まだ間に合う「ITパスポート」受験対策 原山先生の短期合格塾

この連載では,4月18日のITパスポート試験の受験に向けて,短い期間で効率良く受験対策を行う方法や,確実に得点するための裏ワザなどを伝授していきます。

連載一覧

gihyo.jp

  • DEVELOPER STAGE
  • ADMINISTRATOR STAGE
  • WEB+DESIGN STAGE
  • LIFESTYLE STAGE
  • SCIENCE STAGE
  • NEWS & REPORT

書籍案内

  • 新刊書籍
  • 書籍ジャンル一覧
  • 書籍シリーズ一覧
  • 新刊ピックアップ
  • ロングセラー
  • 電脳会議

定期刊行物一覧

  • Software Design
  • WEB+DB PRESS
  • Web Site Expert
  • 組込みプレス