06 | 2017/07 |  08

  1. 無料サーバー

User forum-FC2BLOG-Info-Edit Template-Post-Edit-Upload-LogOut

CSSやJavascript自習の苦闘史を綴っていきたい。恐縮ですがJavascriptを有効にしてご覧ください。
2005年12月から社会問題も掲載!

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

 

jQuery() の挙動を解読する(3) jQuery.extend()及びjQuery.prototype.extend()──jQuery解読(7)

このエントリイの改訂履歴
  • 初稿:2007/11/6
  • 改訂:2008/1/4……多くのミスがあったため全面更新しました。
  • 再改訂:ver1.3.2 対応とするために全面改訂しました。
jQuery.js 1.3.2 においてこのエントリイが対象とする箇所
562:jQuery.extend = jQuery.fn.extend = function() {
    ・・・・
610:},

extend メソッド解読の必要性

話が前後してしまいますが、先に進む前に extend メソッドを解読しておく必要があります。

まだ init() メソッドの解読途中ですが、先に進むためには init メソッド内の随所に鏤められている、extend ( { key1:fn1(){}, key2,fn2(){}, ・・・ } ) メソッド実行によって拡張された、jQuery クラスメソッドを解明しなければならず、そのためにはまず extend() による拡張がどの様に行われるのか、押えておく必要があるからです。

以下に jQuery.js の行を辿って解読しますが空白行は省略します。

※ extend 定義コードは ver1.1.4 以降において、以前よりも大幅に拡張されました。deep copy 対応や未定義値への対応が盛り込まれたためです。更に1.2.2以降においても再拡充されました。こうしてより一般化されました。

変数定義

562:jQuery.extend = jQuery.fn.extend = function() {
563:  // copy reference to target object
564:  var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;

562 行で、jQuery オブジェクトの extend メソッドと jQuery.prototype オブジェクトの extend メソッドを同時に定義しています。( jQuery.fn は 35 行で jQuery.fn = jQuery.prototype と定義済みのショートカット )

これにより、ユーザーが何らかのオリジナルな jQuery.extend( any codes ) を Web サイト内で定義した場合、any codes はそのページが読み込まれた時に prototype オブジェクトのプロパティにもなり、これが jQuery オブジェクトに継承されますから、サイトを開いた時点で、当該の any codes は jQuery オブジェクトに登録済みとなります。

続いて 563 行で変数を 5 つ定義しています。extend() メソッドの第1引数( それが与えられていなければ空オブジュクト )への参照を target に、インクリメント変数となる i に初期値1を、引数の数を length に、deep に偽値を各々代入し、options を未定義値として定義しています。

ここに deep は後に見るように、jQuery ではない複数オブジェクトの統合を行う場合に重要な役割を果たします。

deep copy ── オブジェクトの merging を行う

コメント #563 にあるdeep copy situation とは何か。──調べましたが既製の日本語の解説は見あたりませんでした。「オブジェクトの merge 」そのものを指す言葉ではなくメモリの使い方に係る専門用語のようですが解明出来ていません。

それは兎も角、コード解読を進めます。

第 1 ブロック 566-572 行

566:  // Handle a deep copy situation
567:  if ( target.constructor == Boolean ) {
    // ユーザーが第一引数を "true" とした場合にのみ、deep == true となる
568:   deep = target;
569:   target = arguments[1] || {}; // 第二引数がない場合には空オブジェクト
570:   // skip the boolean and the target
571:   i = 2; // こうしてコピー元からインクリメントを始める。
572:  }

第一引数が Boolean 型だった場合には、この値が既に代入済みとなっている target ( 564 行 )を 568 行で deep に代入します。この結果 deep 値は定義時には false に特定されていましたが true か false となります。

こんな面倒な処理の理由は以下のような複雑なコード進行をさせるためです。

■ 第一引数が true である場合

564 行において deep 値は false とされますが、直後の 567 行により true に置き換えられます。つまり、arguments[0] == true の場合には常に deep ==true となります。これにより、596 行の if の最初の条件がクリアされ、copy 値がノードではないオブジェクト型ならば、jQuery.extend() メソッドが再帰呼び出しされ、こうして第 2 引数オブジェクトに、第 3 引数以降のオブジェクトが deep コピーされます。

ところが、再帰呼び出しされた jQuery.extend() メソッド内では deep は必ず false となります。何故ならば 597 行により第 1 引数とされた deep 値が何であれ、直後に実行される 564 行により、deep = false と強制的に置き換えられてしまうからです。

この結果、再帰呼び出しされた jQuery.extend() メソッド内では 596 行の if 条件は必ず false となって必ず 603-604 行が実行され、プロパティ複写が行われます。

こうして 597-600 行の再帰呼び出しは必ず一度しか実行されないことになります。

では、arguments[n] ( n ≧ 3 )が存在した場合にはどうなるのでしょうか?

一度しか再帰呼び出しされない jQuery.extend() メソッド内において、 2 ≦ i< n+1 迄繰り替えされる for loop ( 584-606 行)によって、arguments[2]~arguments[n] 迄のオブジェクトが順にピックアップされます。

ピックアップされた arguments[i] オブジェクトに対して、次に 588 行の for in loop によって全てのプロパティが走査され、そのプロパティが 589-593 行及び 603-604 行により arguments[1] オブジェクトに複写統合されます。

■ 第一引数が false である場合

この場合には 568 行でも deep は false のままとなるため、597-600 行の extend メソッドの再帰呼び出しは決して行われません。他方意味のあるextend メソッドコードならば、false 以外にも引数は必ずあるはずですから、579-582 行が実行されることはなく、こうして jQuery オブジェクトの拡張は行われません。

その代わり、584-606 行の二重 for loop(但し、595-600 行は決して実行されない)によって、arguments[1] オブジェクトに対する arguments[m](m≧2)オブジェクトのマージが履行されます。

■ 第一引数が Boolean 型ではない場合

このときには 584 行の for loop つまり extend メソッドの引数に対する繰り返しピックアップは実行されますが、596 行の if 条件は必ず false となるため、597-600 行の extend メソッドの再帰呼び出しは決して行われず、604行のプロパティ複写が繰り返されます。

しかも、584-606 行のブロックは、extend メソッドの引数が 1 つしかない場合でも、複数個ある場合でも等しく機能しますので、前者の場合には jQuery オブジェクトが、後者の場合には arguments[1] オブジェクトが、それぞれ拡張されるわけです。

次に target 値に第二引数(なければ空オブジェクト)を代入します。

そしてインクリメントを 2 から開始するように、i の値を変えます。この i=2 は ver 1.1.4 では存在せず、そのためにバグとなっていた箇所です。

▲ToTop

引数がオブジェクトでも関数でもない場合の処理

574: // Handle case when target is a string or something (possible in deep copy)
575: if ( typeof target !== "object" && !jQuery.isFunction(target) )
576:  target = {};

target に空オブジェクトを代入していますが、これはエラーとせずに何も起こらないようにするエラー回避処理です。

引数が唯一の場合の処理──jQuery オブジェクト拡張の前処理

578: // extend jQuery itself if only one argument is passed
579: if ( length == i ) {
580:  target = this;
581:  --i;
582: }

たった1つの引数しか与えられない場合の処理が記されています。this つまり、jQuery オブジェクトを変数 target に代入し、インクリメント変数の初期値をゼロとしています。この i = 0 は 584 行以降で意味を持ちます。

ここにおいて、this(つまり jQuery オブジェクト)を target に代入することは、これより先で jQuery オブジェクト自体を拡張するための前処理となります。

愈々オブジェクトの統合

   // 583 行迄に定義した i を初期値とし引数個数未満迄インクリメントする
584: for ( ; i < length; i++ ) // オブジェクト走査ブロック開始
585:  // Only deal with non-null/undefined values
    // options に i 番目の引数を代入し、それが null でなければ、for loop を実行する
586:  if ( (options = arguments[ i ]) != null )
587:   // Extend the base object. 以下の loop で base オブジェクトを拡張する
     // 統合される側の options オブジェクトのプロパティをリストアップする定番 loop コード
588:   for ( var name in options ) { // プロパティ走査ブロック開始
      // target の name プロパティ値を変数 src に、また  options の name プロパティ値を
      // 変数 copy に代入。こうして src は base オブジェクトの name プロパティ
      // 値となり、copy は複写される統合元オブジェクトの name プロパティ値となる。
589:    var src = target[ name ], copy = options[ name ];
590:
591:    // Prevent never-ending loop
      // プロパティ値が同値ならば
592:    if ( target === copy )
593:     continue; //処理を中断し、次の繰り返しを実行する。( Back to #584 )
594:
595:    // Recurse if we're merging object values
      // オブジェクト同士を統合する場合には extend メソッドを再帰呼び出しする。
      // deep が true で copy が存在して DOM ノードではないオブジェクトの時には
596:    if ( deep && copy && typeof copy === "object" && !copy.nodeType )
       // extend を再帰呼び出し、再帰呼び出しされた jQuery.extend において
       // target = deep、length = 2、deep=false となり、567-572 行のブロックが機能し、
       // 569 行の target には 599 行の src、又は空配列か、空オブジェクトが代入され、
       // 571 行により i の初期値が  2 となる。次に、target(= src)がオブジェクトならば
       // 575-576 行はスルーされ、また length は 3 なので、579-582 もスルーされ、
       // 584 行に辿り着く。586行で options に copy が代入され、そのプロパティリスト
       // アップのための for loop が再び始まる。
       // ここに、再帰呼び出しされた場合には deep == false となっているので、
       // 596 行はスルーされて 603 行が実行され、copy が未定義でないならば、604 行が実行される。
597:     target[ name ] = jQuery.extend( deep, 
598:      // Never move original objects, clone them
599:      src || ( copy.length != null ? [ ] : { } )
       // 初期値 i = 2 なので 586 行により options には
       // 3番目の引数である次行の copy が代入される。
600:     , copy );
601:
602:    // Don't bring in undefined values
      // deep == false 等の場合に 603 行が実行され、604 行により
603:    else if ( copy !== undefined )
       // copy 値が、target オブジェクトの name プロパティ値として代入され、
       // コピー元オブジェクトの nameプロパティが、targetオブジェクトに複写される。
       // 再帰呼び出しの場合も同様の処理が行われる。
604:     target[ name ] = copy;
605:
606:   }
607:
608: // Return the modified object
   // 更新された target オブジェクトが返される。
   // 再帰呼び出しの場合も更新された target オブジェクトが返される。
609: return target;
610:};
興味深い for loop 記述

584 行の for ループに初期値がなく「 ; 」しかないことに注目しました。「 ; 」が2つなければ for 文として成立しませんから「 ; 」は不可欠ですが、初期値が記述されていないのです。

しかし、初期値 i は、既に定義されています。引数が1つの場合には 0 、deep 値が Boolean の時には 2、その他は最初に定義された1です。

このような for ループの標記には初めてお目に掛かりましたが、初期値を随意に変更するこの手法は大変勉強になります。

更にこの for 文には { } がありませんから、for 文は次の 1 行にしか係らず、さらにその当該行は if 文でありこの行にも { } がありませんので、結局、584 行の for ループは、auguments[i] が空でない場合( 586行 )にのみ機能して、588 行以下が働くことになります。

▲ToTop

extend メソッドの要所!

584-606行は extend 関数の引数が null 値でなかった場合に(586行)、オブジェクトを順に対象として、そのプロパティを取り出して別のオブジェクトに統合するコードで、jQuery オブジェクトを拡張するか、複数オブジェクトを統合合体します。

jquery.js の extend() メソッドの引数は JSON オブジェクトとして記述され、その中で様々な名称と値(殆ど関数)が定義されています。584-461行の for loop によって、 1 以上の引数プロパティから順番にプロパティ値を取り出し、それを target オブジェクトに格納してから、最後にこのオブジェクトを return することにより、1以上の個数の引数オブジェクトの各種プロパティを jQuery、又は任意のオブジェクトのプロパティ又はメソッドに複写します。

別エントリイ(jQuery() の挙動を解読する(27) 事例による jQuery.extend() 学習 upon ver1.3.2──jQuery解読(41))に、jQuery オブジェクトを拡張する場合と、任意のオブジェクトを統合する場合の具体例を幾つか記して、復習とします。

▲ToTop

 

■ コメントの投稿 ■

管理者にだけ表示を許可する

●トラックバック●

■トラックバックURLはこちら■
http://hkom.blog1.fc2.com/tb.php/576-96c223cf

●参照元一覧●

<provided Fc2>
<provided i2i>

▲ToTop

 90%近いシェアを握っているインターネットエクスプローラの描画エンジンを利用したタブbrowser。沢山のタブbrowserがあるが、多機能、カスタマイズフリー、スクリプト利用等で一日の長がある。Gekkoエンジンへの対応も行われ、IEからの自立独立の方向に向かっている。2005年7月にはIE7が登場する見通しの中で、今後の発展が望まれる。

 多様なCSS作成支援機能を備えた、タグ入力式 HTML&CSS作成支援エディタ。スキンデザインもすっきりしている。テキストエディター上で作成するよりも確実で安全にタグ打ちが出来る。
文字コードを選べないのが欠点。

 StyleNote同様のタグ入力式 HTML&CSS 作成支援エディタ。長年使用してきたが現在StyleNoteに乗り換えつつある。

 クリップボード履歴情報を活用する為のソフト。画像まで履歴を取ってくれるのが嬉しい。このソフトを使わない日は絶対ない程に重宝し、愛用している。

 起動中のウィンドウの「コピーできない」説明文などの文字列を取得し、コピー可能な文字データにするツール。何かと便利。

 ストリーミングデータを保存することが出来るソフト。動画利用には不可欠なソフトだ。

 無料ながらレイヤー機能を有し、スクリプトによる拡張も可能な、sleipnir作者が提供している優れもの画像編集ソフト。

 画面キャプチャソフトと言えばこれに勝るものなし、ではないだろうか? 様々な取得方法を有しており、ブログ作成にもHomepage作成に不可欠だ。Jtrimと並んでWoodyBellsの作品。

 複数ファイルの同時編集は出来ないが、透過pngも作れる画像編集ソフト。
(以下当該サイトから抜粋)初心者にも簡単に操作が出来るフォトレタッチソフトです。多くの加工機能で画像に様々な効果を与えることができます。非常に軽快に動作するため、ストレスなく操作できます。

 Animation Gifファイルを作れる無料ソフト。

 キャプチャソフト。画面内にサイト全体が表示しきれない場合でも、これを使えば全体をキャプチャすることが出来る。

 画像処理。画像のフォーマット変換のみならず、色数やサイズ、圧縮率の変更まで一括処理できてしまう『BatchGOO!』は、大量の画像をまとめて処理したいときに大変便利なソフト。BMP, TIFF, JPEG, PCX, PNG の相互変換をはじめ、色数・サイズ・解像度の統一、JPEG圧縮率の調節など、ホームページ用の画像や携帯電話用の壁紙を揃えるのに抜群の相性を見せる。(Vectorの当該ソフト紹介頁より抜粋引用)

 名前から直ぐに想像が付くように画像のサイズを測るためのソフトだ。Homepage作成には欠かせない。2カラム、3カラムのレイアウトを行う場合に大変重宝する。

 ランチャーソフトは沢山あるが、中でもこれが一押しだ。2年以上使ってきたがその操作性には毎日満足している。これを使い始めてからデスクトップには一切のアイコンを表示することをやめてしまった。

 AdobeReader7によって、起動時間が長すぎるという長年のユーザーの不満はある程度解消した。そのためこの高速化ソフトは存在価値が低下してしまったかもしれない。AdobeReader6迄はこのソフトによる起動高速化で恩恵を受けてきた。

 IE専用が難点だが、様々なサイト内でIDやパスワードを入力するのに重宝するソフト。コンテキストメニューから簡単に起動できるのがGood! sleipnir等のIEの描画エンジンを利用しているブラウザでも使える。

 利用しているパソコンの諸元値を取得するには、このソフトがベストだ。インストール済みソフトの一覧が取得できるのも嬉しい。

 WMPは機能が豊富なだけ重い。RealPlayerも同様だ。そこでMedia Player Classicを使いたい。動作が軽快なだけではなく、対応しているファイル形式もすこぶる多く、これひとつで、wmvもrmも表示できてしまうのだから凄い! 数多あるMedia Playerの王様と言えるだろう。

 自宅でPCを起動しているときには必ず起動しているメディアプレーヤー。何かと過剰なWinampよりも、起動も速くスキンはシンプルだ。

 DivX, Xvid, Mov, Vob, Mpeg, Mpeg4, avi, wmv, dv, などの動画をDVD-Video形式に変換できるフリーソフト。クリックするとDVD関連ソフト紹介サイト=「DVDなToolたち」なるHomepageが開きます。

----------
200711060115
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。