05 | 2017/06 |  07

  1. 無料サーバー

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

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

スポンサーサイト

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

 

jQuery() の挙動を解読する(9) jQuery.map()メソッド解読 upon ver1.3.2──jQuery解読(13)

このエントリイの改訂履歴
  • 初稿:2007/11/14
  • ver1.3.2 対応改訂:2009/3/18

全く知りませんでしたが、「map」とはプログラミング界では一般的な専門用語のようです。ある関数の引数として別の関数を受け取る関数を「高階関数(higher-order function)」と呼ぶらしい。その結果、ある配列の各要素を対象として順番にそれを操作した結果を返す関数を作ることが出来る、ということらしい。

C言語やPerlなどでは一般的なようですが、Javascriptの場合実装されてないため、each()メソッドと同様に、フレームワークで色々と工夫されている模様です。

cf. こちらに数少ないJavascriptの高階関数の説明があります。
第2回 JavaScriptの関数をマスターしよう - @IT

$.map()の例

まずjQuery.js 1.1.4の解説にあった例題を掲載します。

  • $.map( [0,1,2], function(i){ return i + 4; }); //result [4, 5, 6]
  • $.map( [0,1,2], function(i){ return i > 0 ? i + 1 : null; }); // result [2, 3]
  • $.map( [0,1,2], function(i){ return [ i, i + 1 ]; }); //result [0, 1, 1, 2, 2, 3]

これらの例によって、$.map()を使って、単純に配列要素に加算したり、条件づけて配列要素数さえ増減させたり、自在に加工出来ることがよく分かります。

そこで$.map()の定義を踏まえて独自のサンプルを作ってみます。

$.mapの定義から、引数となる関数には2つの引数(元の配列の各要素とインクリメント値)を渡していますので、jQuery.js1.1.4のサンプルではなかった2つの引数を取る場合を作成してみました。

▲ToTop

$.map() メソッド解読

このエントリイのjQuery.js 1.3.2における対象箇所
1146: map: function( elems, callback ) {
1147:  var ret = [];
1148:
1149:  // Go through the array, translating each of the items to their
1150:  // new value (or values).
1151:  for ( var i = 0, length = elems.length; i < length; i++ ) {
1152:   var value = callback( elems[ i ], i );
1153:
1154:   if ( value != null )
1155:    ret[ ret.length ] = value;
1156:  }
1157:
1158:  return ret.concat.apply( [], ret );
1159: }
1160:

map() メソッドの要所は 1152 行の var value = callback( elems[ i ], i ); にあります。map メソッドの第二引数である関数 callback の第一引数に、mapメソッドの第一引数である配列の各要素を渡し、その演算結果を value に代入し、この value を新たな配列 ret の要素として取込んでいます。これを元の配列要素数だけ繰り返した上で、作成された配列 ret を map メソッドの返値として返しています。

map() にはもう 1 つ注目すべき箇所があります。それは 1158 行の return 値です。

単に return ret ではなく何故 return ret.concat.apply( [], ret ) とするのか、その理由を以下で考え解明します。

実は ver 1.2.6 では該当箇所は次のようになっていました。

▼jquery.js ver 1.2.6
1187:    ret = ret.concat( value );
1188:  }
1189:
1190:  return ret;

concat() を使うことにより、value が配列の時には要素に分解してから ret に取込み最後に ret を返しています。

一方、1.3.2 では まず ret に単純に value を取込んでから、要素の取り込みが終わった配列 ret に対して concat 処理を施して、配列内配列をシリアライズしています。

▼jquery.js ver 1.3.2
1155:    ret[ ret.length ] = value;
1156:  }
1157:
1158:  return ret.concat.apply( [], ret );

どうして jquery.js ver 1.3.2 で #1155-1158 が変更されたのか、最初は疑問に思いました。そこで原点に返って concat メソッド自体を復習することにしました。

▲ToTop

concat() メソッドについて

少し脱線しますが、concat() メソッドの基本を振り返ります。

concat は或る配列に新たな要素を追加するメソッドですが、追加される要素自身が配列である場合には、その配列を要素に分解してから、元の配列の要素として追加します。いわば線形化するわけです。

例題を作ってそれを通じて学習を確実にしたいと思います。

■ 例 1
 var ary =[1,[5,8],4,9];
 ary.concat(10,[15,80]) //return: [1, [5, 8], 4, 9, 10, 15, 80]
 /* 組み込み元の配列 ary の要素配列 [5,8] は concat 後もそのまま
   ですが、引数の配列 [15,80] は、シリアライズされ、15,18 と分解されて
   配列 ary に取込まれています。
 */

しかし、次のように引数の配列内に更に配列が内包されている場合には、それはシリアライズされません。

■ 例 2
 var ary =[1,[5,8],4,9];
 ary.concat( 10, [15, [ "test", "sample" ] ] );
   //return: [ 1, [5, 8], 4, 9, 10, 15, ["test", "sample"] ]
 /* 配列 ary の要素である配列 [5,8] は concat 後もそのままですが、
   第 2 引数の配列 [15,["test","sample"]] は、外側だけシリアライズされ、
   15, ["test", "sample"] となりますが、["test", "sample"] は分解されません。
 */

▲ToTop

ary2.concat.apply(ary1,ary2) メソッドについて

map() メソッドの 1158 行 return ret.concat.apply( [], ret ) を分析するために、幾つかの例をチェックしてみます。なお、チェックには Firefox 3.0.7、Firebug 1.3.3 を使いました。

以下の 4 つの微妙に異なる concat メソッドの結果を比べると幾つかのことが分かります。

■ 例 3
 var ary =[1,[5,8],4,9];
 var ret =["昨日",["今日",500]];
 ary.concat.apply(ret,ary)    //["昨日", ["今日", 500], 1, 5, 8, 4, 9]
 ret.concat.apply(ret,ary)    //["昨日", ["今日", 500], 1, 5, 8, 4, 9]
 ary.concat.apply(ary,ret)    //[1, [5, 8], 4, 9, "昨日", "今日", 500]
 ret.concat.apply(ary,ret)    //[1, [5, 8], 4, 9, "昨日", "今日", 500]
  • concat.apply(a,b) メソッドは、第 2 引数配列だけを要素に分解する。
  • 結果配列の要素順は、apply メソッドの引数順となる。
  • 結果配列の要素順は、concatを a,b どちらの配列のメソッドとして作用させるかに無関係である。

▲ToTop

改めて map() メソッドの #1155-1158 について

以上を踏まえて map() メソッドの #1155-1158 を解明します。

▼jquery.js ver 1.3.2
1155:    ret[ ret.length ] = value; // ここでは単なる代入だけを行う。
1156:  }
1157:  // ここで一回だけconcat()を使用し、ret 配列内の配列を分解し ret
     // を更新する。ここに [].concat.apply( [], ret ) でも全く同様の
     // 結果が取得できる。しかし、concat.apply( [], ret ) ではエラーとなる。
1158:  return ret.concat.apply( [], ret );

▼jquery.js ver 1.2.6
       // イテレートの度に concat() メソッドを起動している。
1187:    ret = ret.concat( value );
1188:  }
1189:
1190:  return ret;

要点は以下の点です。単なる代入よりも時間を要する cancat() メソッドをイテレートする回数だけ起動する( ver 1.2.6 )よりも、最後に 1 回だけ concat() を起動する( ver 1.3.2 )方が全体の処理時間が短くなる。

Firebug を使って本当に処理時間が変わるのかを調査し、確認出来た

以下のサンプル結果により、concat() 適用回数を減らすことにより明らかに処理時間が短いことが分かります。

このサンプルは5000回loopさせながら、同一の 2 つの配列を作るものです。変数定義時点からタイマーをスタートさせ、コンソール出力させてからタイマーを止め、その間の所用時間を計測しました。

▼毎回 concat() 適用の場合
console.time("Timers")
var i = 0, ary = [], ret = [];
while ( i < 5000 ){
    ary.push( i );
    ret = ret.concat( ary[i] );
    i++;
}
console.log(ret);
console.timeEnd("Timers"); // 計測結果 Timers: 1035ms

▼最後に一回だけ concat() 適用の場合
console.time("Timers2")
var i=0,ary=[],ret=[];
while ( i < 5000 ){
    ary.push( i );
    ret[i] = ary[i];
    i++;
}
    ret.concat.apply([], ret)
console.log(ret);
console.timeEnd("Timers2"); // 計測結果 Timers2: 669ms 半分以下で完了!

 

■ コメントの投稿 ■

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

●トラックバック●

■トラックバックURLはこちら■
http://hkom.blog1.fc2.com/tb.php/581-68248d8a

●参照元一覧●

<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が開きます。

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