04 | 2017/05 |  06

  1. 無料サーバー

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

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

スポンサーサイト

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

 

jQueryに学ぶJavascriptの基礎(1) return 値は「何に」返されるのか?──jQuery解読(16)

jQuery 解読作業を進めるにつれ、Javascript の基礎が如何に分かっていないか、ほぼ毎日のように痛感させられます。その意味では jQuery 解読は無謀なチャレンジであった訳ですが、それでも誤謬を犯すマイナスを埋め合わせて遙かに余りあるプラスがあることも毎日自覚されるので、恥を忍んで引き続きjQuery解読を進めるつもりでいます。

しかし、基礎の基礎が余りに分かってない自分に嫌気が指してきてしまい、匙を投げ出すような醜態は演じたくありません。そこで、自戒を込めて敢えて誤解していたこと、理解していなかったこと、不十分な理解に留まっていたことなどについて、つらつらと記述していきたい、と思います。

ここでは return 値の受け取り先について、『Javascript第5版 日本語訳』における記述の曖昧さを指摘すると共に、jQuery()関数実行過程における return 値についてまとめたいと思います。

本稿の目的とは関係ないが・・・return の 返値

四則計算のような簡単な関数の場合、return で返される値は余りに明白です。return a*b ならば a に b を乗じた計算結果が返値になります。

また return Boolean の場合には true か false が返されます。そして同時に或る関数から true や false が返された場合のJavascriptの振る舞いについても、状況に応じた一定の決まり事があるようです。( status行に関するコードやタグ属性として記述された Javascript 文の場合等)

一般に、返値は数値、文字列、論理値及びオブジェクトのいずれでもあり得ます。クロージャーの場合のように関数自身を返値とすることさえある訳ですから、返値はあっさり言えば Javascript で扱えるものならば「何でもあり」と思います。

return はそれを含む「関数の呼び出し元に返値を返す」

『Javascript第5版』には「return はそれを含む「関数の呼び出し元に返値を返す」」と書いてあります。

関数がリテラル標記されている場合で右辺の関数が無名だった場合について考えてみます。

jQuery関数もこのように無名関数として定義されていますが、例えば、
   var funcName = function (a,b) {return a + b };
のような場合です。

この関数は funcName(2,3) のような標記によって呼び出され return すべき値として 5 を算出します。この場合の呼出し元はグローバル変数 window です。

勿論、変数 funcName に返値 5 が代入されるのではありません。funcName は関数オブジェクトそのものであって、alert( funcName ) で出力すれば function (a,b) {return a + b } が表示されます。

以上のことは、関数標記を function funcName(a,b) {return a + b } とすればより分かりやすくなるかもしれません。こうすればここには返値の受け取り先は何もありませんが、受け取っているのはwindow オブジェクトです。

さて、返値を取得するには var result = funcName (2,3) のように関数の返値の受け取り先を明示的に指示しなければなりません。こうすれば変数 result に 返値 5 が代入されます。

但し、それは呼出し元に返された return 値が 変数 result に代入されているからです。返値を最初に受け取る受け取り先は 決して変数 result でもなければ、funcName 関数オブジェクトでもなく window オブジェクトです。funcName (2,3) により window オブジェクトに返された返値が代入式によって result に代入されているに過ぎません。

以上は余りに当たり前のことですが後述することとの関係でまず確認のために記しました。

▲ToTop

メソッドの場合の返り先

よく知られているように、無名関数をあるオブジェクトのプロパティ値に設定する場合、つまり或るオブジェクトのメソッドにするには obj.meth = function (a,b) {return a + b }; とします。

この場合オブジェクト obj のプロパティである meth に関数オブジェクトへの参照が代入され、実行演算子()を使って obj.meth(3,4) のように指示してこの関数が実行されます。

では、この場合の返り先はどこでしょうか? それはオブジェクト obj の meth プロパティです。

さて、ここから本題です。『Javascript第5版』では次のような一説があります。

オブジェクトを介して呼び出す関数のことをメソッドと呼びます。メソッドを呼び出したオブジェクトは暗黙的に引数として関数に渡されます。(p.123)

この文章を読むと、メソッドの場合の呼出し元は当該オブジェクトであり、他所で「関数の呼び出し元に返値を返す」と書いてあるのだから、メソッドの返値はそれを呼び出したオブジェクトに受け取られる、と理解してもおかしくありません。

しかし、オブジェクトはメソッドの呼び出し元ではありません。返値はオブジェクトに返される訳ではありません。オブジェクトを介して、オブジェクト上で、当該関数が実行されるだけです。

「オブジェクトを介して呼び出す」との表現と「メソッドを呼び出したオブジェクト」という表現は微妙に意味が異なります。介して呼び出された場合の呼出し元は、決して介されたオブジェクトではないのです。従ってメソッドを呼び出したオブジェクトという表現は適切さを欠くと言わざるを得ないでしょう。

この曖昧な表現故に、少なくとも私は、メソッドの場合には当該オブジェクトに返値が返される、と誤解させられたのですから。

「メソッドを呼び出したオブジェクト」は原典では「When a function is invoked on an object, the function is called a method, and the object on which it is invoked is passed as an implicit argument of the function.」(アンダーライン部が「メソッドを呼び出したオブジェクト」と訳された箇所)です。アンダーライン部を直訳すれば「それ(メソッド)がその(オブジェクト)上で呼び出されたオブジェクト」はとなり「メソッドを実行したオブジェクト」と表現した方が、「呼出し元」なる表現との差異を明確にするためにも適切ではないか、と思います。

呼出し元が或るオブジェクト上(あるいは「内」)の1つのプロパティである、メソッド関数を実行し、その結果が呼出し元に返されるのですから。

一方「return文が指定されていれば、関数の実行はここで中断され、式の値(もしあれば)が呼び出され呼出し元へ返されます(p.124)」は原典では「it causes the function to stop executing and to return the value of its expression (if any) to the caller.」です。callerは訳すと確かに「呼出し元」となります。

つまり call と invoke をそれぞれ異なる適切な言葉で表現すべきであって、共に「呼び出す」と訳していることが読者に混乱を招いている、と思います。

▲ToTop

返値を jQuery() の定義コードで見てみると...

定義によれば、jQuery() には jQuery.prototype.init メソッドをコンストラクタとするインスタンス(仮にこのインスタンスを insObj とします)が return されます。(jquery.js Ver 1.3.1 の場合には 24~27行)

コンストラクタ・プロトタイプの仕様から、insObj は init メソッドの prototype オブジェクトのプロパティを継承しますが、この init.prototype は、jQuery.prototype オブジェクトのプロパティを継承するように設定されています。(同532~533行)

この結果、insObj は init メソッドの返値及び jQuery.prototype オブジェクトから継承したプロパティを持つことになります。

かくして、insObj を受け取る jQuery() は init メソッドの返値及び jQuery.prototype オブジェクトから継承したプロパティを持つことになります。

以上のことをjQueryの this.init() で呼び出された init() メソッドでチェックしてみます

<1>
	55:	this[0] = tmp;
	56:	this.length = 1;
	57:	return this;
<2>
	65:	return new jQuery( context ).find( selector );
<3>		
	72:	return this.setArray([ selector ] );

init() メソッド内には this を直接返す場合(<1>)、新たなインスタンスを返す場合(<2>)、this.setArray() メソッドを返す場合(<3>)など様々な return 値があり大変勉強になります。

まずreturn値の返り先について。

下記コードの進行過程を具に解析する作業を通じて返値を解析してみます。

var jQuery = function (a,c){
	return  this instanceof jQuery ? this.init(a,c) : new jQuery(a,c)
}
  1. ユーザーが jQuery(x、y) を実行する。
  2. インクルードされている jQuery.js 内の jQuery(x,y){・・・} が呼び出され実行される。
  3. この時 this は window オブジェクトを指しているから、3項演算子で条件分岐されて new jQuery(x,y) が実行される。つまり new 演算子によって jQuery インスタンスオブジェクトとして新しい空オブジェクトが生成され、かつ、今度は jQuery(x,y) がコンストラクタ関数として呼び出され、その中で使われる this は 仕様上当該のインスタンスオブジェクトを指すことになる。
  4. コンストラクタ関数として呼び出された jQuery(x,y) では、今度は this instanceof jQuery == true となるので、条件分岐されて this.init() が実行される。
  5. ところでその先が興味深い点である。 return this.init()とcoding されているから、ここから呼び出し元を逆順に辿って順次返値が返されていく。さてその最終の受け取り先は?
  6. その受け取り先こそ、ユーザーが記したjQuery(x,y)に他ならない。そもそもユーザーが記述したコードによって起動された jQuery.js内のjQuery(x,y)関数 が、その内部処理を経て return 値をユーザー側の入力 API に返すからこそ、メソッドチェーンと言われている、jQuery(●,■).×××().△△() のような連鎖的なAPIが可能となるのである!

因みに、jQuery()は var jQuery = function(){・・・return this.init()} というリテラル形式関数ですから、先に見たように無名関数から返された return 値はこの式内では受け取れません。受け取り先はこの関数を呼び出したもの、つまりユーザーが入力した jQuery(x,y) に他なりません。

また蛇足ながら、returnチェーンこそがメソッドチェーンを実現している「 秘策 」に他なりません。

▲ToTop

各々のケースの解読
<1>return this

55行:this[0]にtmpが代入されます。つまりインスタンスの最初の要素がtmpとなります。

56行:次にその配列の要素数が1とされます。これによりもし要素数が2以上であった場合であっても強制的に1となります。

57行:最後にこうして加工された this、つまりインスタンスが jQuery()関数に 返され、最終的にユーザー入力 API に返されます

実は、jQueryではインスタンスがjQuery()関数に返されるシーンは結構沢山あります。それこそがjQuery.jsの神髄とも言えるメソッドチェーンを実現するために、こうした仕様となっているのでしょう。

<2>return Instance

これは細かく説明するまでもなく、new 実行後の新たなインスタンスがjQuery()関数に返され、それがユーザー入力 API に返されることになります。

<3>return this.setArray

この場合には setArray() メソッドを分析すれば、Array.prototype.push.apply( this, a ) によって、取得されたエレメントノードを要素とする配列がインスタンスオブジェクトに返され、それが init() からの返値となり、結局それがユーザー入力 API に返されることになります。

<結論>
以上から、全ての場合においてインスタンスオブジェクトが init() メソッドから返され、それが jQuery() 関数の連鎖を通じて、ユーザー入力 API に返されることになります。
見えないインスタンス

以上のように、this キーワードと return が組み合わされて使用されると、一見複雑に見えます。jQueryでは生成されるインスタンスを明示的に固有の変数に代入しませんので、インスタンスオブジェクトが直接変数としてコード内に出現することはありません。、それは常に this によって指し示されるだけであり、このことがコードの理解をより一層分かりにくくしているのではないか、と痛感しています。この見えないインスタンスに散々苦労させられたのは、私自身に他なりませんから(苦笑)。

▲ToTop

それにしても記憶先はどこか?

命令 funName() あるいは obj.meth() それ自体は関数オブジェクトではなく関数の実行です。これに返値が返されることをこれまで見てきました。では返された return 値は一体どこに記憶されるのでしょう?

もちろん物理的にはメモリ上ですが、Javascript においてどこに保存されるのでしょうか?

裏返せば変数に代入されない返値を参照する何らかの方法はあるのでしょうか?

関数が定義されると Call オブジェクトが生成され、そのプロパティに引数やローカル変数が格納されるそうです。従って関数実行時にはこの Call オブジェクトの中に返値も保存され、代入先の変数等が用意されていれば、Call オブジェクトのプロパティとして記憶された返値が、当該変数等に代入されるのでしょうか?

この Call オブジェクトのプロパティに返値が保存される、という考えは全くの推測に過ぎませんが、他に考えようがありません。

無名関数の返値を変数に代入しないで参照する

次のようにして全く変数に代入されない返値 98 を取得することが可能です。
   var ret= (function() {return arguments[0] + arguments[1]; })(20,78)

また決して好ましい方法とは思いませんが、徒に複雑にしただけの以下のようなクロージャーを使っても同様に返値を取得することが出来ます。

(function () {
  var r=arguments;
  return function() {return r[0]+r[1]; };   
})(20,78)() //これを実行すると 20 + 78 のreturn値である 98 が取得できる。

上のコードは次のように進行します。

まず最初の無名関数 function () の引数に 20と78を代入して無名関数を実行し【(20,78)】、更にその返値として返される後の無名関数を実行して【最後の()】その返値を求めています。

 

■ コメントの投稿 ■

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

●トラックバック●

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

●参照元一覧●

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

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