場合 - みる会図書館


検索対象: JavaScriptパターン : 優れたアプリケーションのための作法
94件見つかりました。

1. JavaScriptパターン : 優れたアプリケーションのための作法

6.12 メソッドを拝借する ー 143 return greet 十・ / / テスト ・十 thiS. name; one. say('hi'); / / "hi, object" 別のオプジェクト two は say ( ) メソッドを持っていませんが、 one から借りることができます。 var two = { name: "another object" one. say ・ apply(two, [ ' he110 ' ]); / / " he110 , another object" します。返された関数はクロージャーに閉じ込めた 0 と m にアクセスできます。このため bind ( ) この bind ( ) 関数はオプジェクト 0 とメソッド m を受け取り、この 2 つを結合した別の関数を返 return m. apply(), [] . slice. call(arguments)); return function ( ) { function bind(), m) { メソッドに固定 ( あるいは東縛 ) できます。 ド全体は期待通りの動作になりません。次のような簡単な関数を使えば、あるオプジェクトをある どちらのケースでも say ( ) 内部で this はグローバルオプジェクトを指しているので、このコー yetanother. method(one. say); / / " H011a , undefined" return ca11back('HoIa ' ) ; method: function (callback) { name: "Yet another object" var yetanother / / コールバックとして渡します say(' h0h0' ) ; / / "h0h0, undefined" var say = one. say; / / this はグローバルオブジェクトを指します / / 変数に代入すると くさんあるので、こうした状況は頻繁に発生します。 す場合、どうなるでしよう。クライアント側のプログラミングでは、イベントやコールバックがた しかし、関数のポインタをグローバル変数に代入した場合、あるいは関数をコールバックとして渡 この例では、 say() 内部の this は two を指すので、 this. name は "another object" になります。

2. JavaScriptパターン : 優れたアプリケーションのための作法

110 ー 5 章オブジェクト作成のバター / / コンストラクタ var Gadget = function ( ) { } ; / / 静的メソッド Gadget. isShiny = function ( ) { return you bet" ・ / / プロトタイプにメソッドを追加 ン Gadget. prototype. setPrice = function (price) { this. price = price; これらのメソッドを呼んでみましよう。静的な isShiny ( ) はコンストラクタから直接呼び出せま すが、プロトタイプに定義したメソッドはインスタンスが必要です。 / / 静的メソッドを呼ぶ Gadget. isShiny(); / / "you bet" / / インスタンスを作成してメソッドを呼ぶ var iphone = new Gadget(); iphone. setPrice(500); インスタンスメソッドを静的に呼び出そうとしても動作しません。同様にインスタンスである iphone オプジェクトを使って静的メソッドを呼び出すこともできません。 typeof Gadget. setPrice; / / "undefined" typeof iphone. isShiny; / / "undefined" インスタンスでも静的メソッドが動くと便利な場合もあります。これはプロトタイプに新しいメ ソッドを追加するだけで実現できます。元の静的メソッドへのフアサード ( 正面玄関 ) として機能し ます。 Gadget. prototype. isShiny = Gadget. isShiny; iphone. isShiny(); / / "you bet" この場合、静的メソッドの内部で this を使うときには注意が必要です。 Gadget. isShiny() を実 行すると、 isShiny( ) の内部の this は Gadget コンストラクタ関数を参照します。 iphone. isShiny() を実行すると、 this は iphone を指します。 次の例では同じメソッドを静的呼び出しと静的でない呼び出しとで少し異なる動きにしていま す。メソッドがどのようにして呼ばれたのか、 instanceof を使って判定しています。 〃コンストラクタ var Gadget = function (price) { this. price = price;

3. JavaScriptパターン : 優れたアプリケーションのための作法

82 ー 4 章関数 パラメータの名前を覚える必要があります。 プロバティ名はミニファイされません。 このパターンは関数で DOM 要素を作る場合や要素の CSS スタイルを設定するときに便利です。 4.10.1 関数の適用 用の正確な意味を考えておきましよう。 最後にカリー化と部分関数の適用について解説します。 4.10 カリー化 要素やスタイルにはたくさんの属性やプロバティがあり、そのほとんどが省略可能だからです。 このテ ーマに深入りする前に、関数の適 純粋な関数プログラミング旨衄においては、関数は呼び出されるものとしてではなく、 「コロロ むしろ適 用されるものとして説明されます。 JavaScript においても同様で、メソッド Function. prototype. apply() を使って関数を適用することができます。 JavaScript において関数は実際にはオプジェク トであり、メソッドを持っているからです。 関数適用の例を次に示します。 / / 関数を定義 var sayHi = function (wh0) { return " He110 " + (wh0 ~ ・ / / 関数を呼び出し sayHi(); / / " He110 " ー十 WhO ・ sayHi('world' ) ; / / " He110 , world! " / / 関数を適用 sayHi. apply(null, ["hello"]); / / " He110 , he110 ! " この例からわかるように、関数の呼び出しも関数の適用も同じ結果が得られます。 apply() には パラメータが 2 つあります。最初のパラメータはこの関数の内部で this に東縛されるオプジェク トです。 2 番目のパラメータは引数の配列で、これは関数の内部で利用可能な a て guments のような オプジェクトになります。最初のパラメータが null の場合、 this はグローバルオプジェクトを指 します。これはまさに、あるオプジェクトのメソッドではない関数を呼んだときに起きる動作です。 関数がオプジェクトのメソッドであるときは、 null を渡してはいけません。そのオプジェクトが apply() の最初の引数になります。

4. JavaScriptパターン : 優れたアプリケーションのための作法

ビスは複数のビデオの ID を受け付けるので、 HTTP リクエストをできるだけ少なくして、 かのビデオのデータを一度にまとめて取得することで、処理を高速化できます。 このアプリケーションはいくつかの ( あるいはすべての ) ビデオを一度に展開できるので、 サービスリクエストをまとめる絶好の機会です。 7.7.1 .2 プロキシがない場合 このアプリケーションの主なアクターは 2 つのオプジェクトです。 videos 77 プロキシー 169 ジに組み込まれていないので、ウエプサービスを呼び出して表示する必要があります。ウエプサー href="http://new.music.yahoo.(0m/Vide0S/ー2144530" 〉 Don't Drink The Water く /a> く /li 〉 href="http://new.music.yah00.com/videos/--217241800">Funny the Way lt ls く /a> く /li> こでイベント処理を見てみましよう。ます $ という略記関数を定義します。 し、くつ ウエプ 情報ェリアの開閉 ( メソッド videos. getlnfo( ) ) とビデオの再生 ( メソッド videos. getP1ayer()) を担当します。 メソッド http.makeRequest() を使ってサーバとの通信を担当します。 プロキシがない場合、 video. getlnfo() はビデオごとに毎回 http.makeRequest() を呼びます。プ ロキシを追加すると、 proxy という新しいアクターが登場し、 videos と http の間に立って、 makeRequest() の呼び出しを代理で受け取り、可能であればリクエストをまとめます。 ますプロキシがない場合のコードを調べて、次にプロキシを追加してアプリケーションの応答性 能を改善しましよう。 7.7.1.3 HTML HTML のコードはリンクのリストにすぎません。 く P> く span id="togg1e-all">Toggle Checked く /span> く /P> http 7.7.1.4 イベント処理 く / 01 > く li> く input type="checkbox" <li> く input type="checkbox" く 1i〉く input type="checkbox' く li> く input type="checkbox" checked> く a く li> く input type="checkbox" く li> く input type="checkbox" く 01 id="vids"> href="http://new.music.yah00.C0m/Vide0S/ー2144532" 〉 What Wou1d You Say く /a> く /li 〉 checked> く a checked> く a ー checked> く a href="http://new.music.yahoo.com/videos/--45286339">Crush く /a> く /li> href="http://new.music.yahoo.com/videos/--4472739">Save Me く /a> く /li> checked> く a href="http://new.music.yahoo.(0m/Vide0S/--2158073" 〉 Gravedigger く /a> く /li> checked> く a

5. JavaScriptパターン : 優れたアプリケーションのための作法

70 ー 4 章関数 / / setup 関数を使う var my = setup(); / / アラートで 1 が表示される my(); / / アラートで 2 が表示される 返される関数は setup ( ) でラップされているので、 setup ( ) はクロージャーを作成します。この クロージャーを使うとプライベートデータを格納することができます。このプライベートデータに は、返された関数からアクセスできますが、外部のコードからはアクセスできません。次の例は毎 回呼ばれるたびに値が増えるカウンタになります。 var setup = function ( ) { var count = 0 ; return function ( ) { return (count + = 1 ) ; / / 使い方 = setup(); var next next(); / / 1 が返る next(); / / 2 next(); / / 3 4.4 自己定義関数 関数の定義を動的に行い、変数に代入することができます。新しい関数を作成し、すでに別の関 数を保持している変数にこの関数を代入すれば、古い関数は新しい関数で上書きされます。これは 古い関数ポインタが新しい関数を指すように再生しているとみなせます。この再生を古い関数の本 体内部で行うことも可能です。この場合、関数はそれ自体を上書きし新しい実装で再定義していま す。実際以上に複雑に思えるでしようから、単純な例を見てみましよう。 var scareMe = function ( ) { a1ert("Boo!"); scareMe = function ( ) { aIert("Doub1e b00 ! " ) ; / / 自己定義関数を使う scareMe(); / / B00 ! scareMe(); / / Doub1e b00 ! このパターンは、関数に初期化による準備作業があり、その準備作業の実行を 1 回きりにする必 要があるときに便利です。回避できるのであれば、作業を繰り返すべき理由はないので、この関数 の一部はもはや必要とされないかもしれません。このような場合、自己定義関数を使って自分自身

6. JavaScriptパターン : 優れたアプリケーションのための作法

16 ー 2 章必須バターン 2.3 fo 「ループ for ループでは配列や配列に似たオプジェクト、たとえば arguments や HTMLC011ection オプジェ クトを繰り返し処理します。通常 for ループのパターンは以下のようになります。 / / 最適化していないループ fo て (var i = 0 ; i く myarray. length; i + + ) { / / mya Ⅱ ay [ i ] に対して何か処理を行う このパターンには、ループの繰り返しごとに配列の長さがアクセスされる点に問題があります。 これによってコードの処理は遅くなります。 mya て ray が配列ではなく HTMLCollection オプジェクト の場合は顕著です。 HTMLC011ection は以下のような DOM メソッドが返すオプジェクトです。 document . forms ページ上の最初のフォームにあるすべてのフィールド document. forms [ 0 ] . elements すべてのフォーム すべての A 要素 document . links ページ上のすべての IMG 要素 document. images HTMLC011ection には DOM 標準以前に導入されたものもあり、今日でも使われています。 ・ document. getEIementsByTagName() ・ document. getEIementsByClassName() ・ document. getEIementsByName() 合わせが発生してしまいます。 DOM の操作は一般に時間がかかるのです。 わせが行われる点です。つまりコレクションの length にアクセスするたびに、 DOM に対して問い コレクションを扱う場合の問題は、それによってドキュメント (HTML ページ ) に対して問い合 このため、 for ループでは配列 ( あるいはコレクション ) の長さをキャッシュしておくのが良いパ HTMLC011ection オプジェクトを繰り返し処理する前にその長さをキャッシュしておくと、あらゆ このやり方だと一度取得した length の値をループ全体で使い回しできます。 / / mya ay [ i ] に対して何か処理を行う for (var i = 0 , max = myarray. length; i く max; i + + ) { ターンになります。

7. JavaScriptパターン : 優れたアプリケーションのための作法

6.10 プロバティのコピーによる継承ー 139 この実装はオプジェクトの「浅いコピー」になります。これに対して深いコピーは、コピーしよう とするプロバティがオプジェクトもしくは配列であるか検査し、そうであれば、そのプロバティの プロバティに対して検査とコピーを再帰的に繰り返します。浅いコピーの場合い avaScript ではオ プジェクトは参照で渡されるので ) 子のプロバティを変更すると、そのプロバティがオプジェクト だった場合、親も同様に変更されてしまいます。 ( 関数もオプジェクトであり参照で渡されるので ) これはメソッドに関しては好ましいですが、他のオプジェクトや配列に関しては困ったことになり ます。次の例を考えてみましよう。 var var kid . dad . dad . dad counts: [ 1 , 2 , 3 ] , reads: {paper: true} = extend(dad); kid counts. push(4); counts. t0String(); / / " 1 , 2 , 3 , 4 " = kid. reads; / / true reads ここで extend ( ) 関数が深いコピーを実行するように変更してみましよう。プロバティの型がオ プジェクトであるか検査して、そうであれば、再帰的にそのプロバティをコピーします。オプジェ クトが配列かどうかの検査も必要です。 3 章で説明した配列かどうかのチェックを使いましよう。 extend ( ) の深いコピーバージョンは次のようになります。 function extendDeep(parent, child) { var 1 , toStr = 0bject. prototype. toString, " [object Array] " astr = child Ⅱ { } ; child for (i in parent) { if (parent. has0wnProperty(i)) { "object") { if (typeof parent[i] ー child[i] = (t0Str. call(parent[i]) = extendDeep(parent[i], child[i]); い実装を検証してみます。 return child; } else { = astr)? 冂・ child[i] = parent[i]; オプジェクトの真のコピーが得られているか、子オプジェクトが親を変更してないか、 この新し

8. JavaScriptパターン : 優れたアプリケーションのための作法

6.3 クラシカルなバターンその 1 : デフォルトバターン一 123 ここで kid. say ( ) を実行すると何が起きるでしよう ? オプジェクト ( 3 ) にはそのようなメソッドが ないので、プロトタイブ連鎖を経由して ( 2 ) が調べられます。オプジェクト ( 2 ) にもそのようなメソッ ドはないので、連鎖をたどって ( 1 ) が調べられて、 こでやっと見つかります。 say ( ) の内部には this. name への参照があるので、これを解決する必要があります。こで再び探索が始まります。 この場合、 this はオプジェクト ( 3 ) を指しますが、 こには name はありません。次にオプジェクト ーーには値 Adam を持つ name プロバティがあります。 ( 2 ) が調べられ 最後にもう一歩先を見てみましよう。次のようなコードがあったとします。 この場合、どのように連鎖をたどるのか、図 6-3 に示します。 kid. say(); / / "Patrick" kid. name = "Patrick" ・ var kid = new Chi1d(); say() ・・ Parent. prototype = Patrick 継承される点です。この固有のプロバティはひとつのインスタンスに固有であり再利用できないこ このパターンの欠点のひとつは、追加した固有のプロバティとプロトタイププロバティの両方が 6.3.2 バターンその 1 を使うときの欠点 が「光臨」し、一連の連鎖の探索で見つかります。 delete kid. name を使って新しいプロバティを削除すると、オプジェクト ( 2 ) の name プロバティ kid. name の探索と同じなので、オプジェクト ( 3 ) ですぐに見つかります。 ソッド say を探し、次に ( 2 ) から探し、最後の ( 1 ) で見つかります。しかし今回の this. name の探索は 有のプロバティが直接作成されます。 kid. say ( ) を実行するとき、ますオプジェクト ( 3 ) からこのメ kid. name を設定してもオプジェクト ( 2 ) の name プロバティは変化しません。オプジェクト ( 3 ) に固 図 6-3 継承しさらに子オブジェクトにプロトタイプを追加した後のプロトタイブ連鎖 name proto new Chi1d() proto name = Adam ・・・ new Parent()

9. JavaScriptパターン : 優れたアプリケーションのための作法

3.3 3.3 new を強制するバターン new を強制するバターン 47 すでに説明したように、コンストラクタは単なる関数ですが new を使って呼び出すことができま 出すと、実際には member というグローバルオプジェクトが作成され、 window. member あるいは コンストラクタ内部に this. member のような何かがある場合、コンストラクタを new なしで呼び は window を指します ) 。 ると、コンストラクタ内部では this はグローバルオプジェクトを指すからです ( プラウザでは this 実行時工ラーにもなりませんが、論理上のエラーとなり予期せぬ振る舞いになります。 new を忘れ す。コンストラクタを呼ぶとき new を書き忘れると何が起きるでしようか ? これは構文工ラーにも console. log(typeof good_morning); / / "undefined" var good morning = Wa 幵 le(); / / new を忘れてしまうと / / アンチパターン : console. 10g ( good morning. tastes); / / "yummy console. log(typeof good morning); / / "object" var good morning = new Waffle(); / / 新しいオブジェクト this . tastes function Wa 幵 le() { / / コンストラクタ う原則に反しています。 member でアクセスできてしまいます。 この振る舞いはグローバル名前空間を汚染しないようにとい this にメンバをすべて追加するかわりに、 that にメンバを追加し、 that を返すのです。 ん。コンストラクタがコンストラクタとして必ず振る舞うようにするためのパターンがあります。 命名の作法に従うと便利なはすですが、それだけで必す正しい振る舞いになるわけではありませ 3.3.2 that を使う (MyConstructor) にします。「通常の」関数やメソッドでは頭文字を小文字 (myFunction) にします。 コンストラクタの名前は、 2 章で説明したように命名の作法に従って、頭文字を大文字 3.3.1 命名の作法 せん。 でコンストラクタを呼び出しても正しく動作するようにしたコンストラクタ関数を使うしかありま はもはやグローバルオプジェクトを指さないようになります。 ES5 が利用できない場合、 new なし この望ましくない動作については、 ECMAScript 5 で取り組まれていて、 strict モードでは this console. log(window. tastes); / / "yummy

10. JavaScriptパターン : 優れたアプリケーションのための作法

24 ー 2 章必須バター (function ( ) { var 10Ca1 ン eval("local = 3 ; console. 10g ( 10Ca1 ) " ) ; / / 3 がログに表示される console. 10g ( 10Ca1 ) ; / / 3 がログに表示される (function ( ) { var 10Ca1 function("console. log(typeof 10Ca1 ) ; " ) ( ) ; / / undefined がログに表示される コーディング作法に対する考え方の違い ( たとえば、コードのインデントに使う文字はタブか空 他のチームメンバーが書いたコードを理解でき、より早い段階で活躍できるようになります。 り、読んで理解しやすくなります。チームに新たに合流した開発者は、この作法に従って読むので、 コーディングの作法を確立しそれに従うことは重要です。一貫性があり見通しの良いコードにな 2.9 コーディングの作法 力に対しては数値を返しますが、それ以外の場合は NaN を返します。 かるように構文解析を行うので、単純な変換ではないのです。 parselnt() は " 08he Ⅱ 0 " のような入 これらの方法は parselnt() を使うより速くなることがあります。 parselnt() はその名前からわ Number("08") / / 8 + " 08 " / / 結果は 8 文字列を数値に変換する方法は他にもあります。 は 0 になります。 (parselnt(year, 8 ) と書いたのと同じになります ) が、 09 は 8 進数として妥当でないので、戻値 ここで parselnt ( year ) のように基数のパラメータを省略すると、 " 09 " は 8 進数と解釈されます year = parselnt(year, 1 の ; month = parselnt(month, 10 ) ; year = var month = "06" 予期せぬ結果を避けるため、必す基数パラメータを指定しましよう。 ECMAScript 3 では 8 進数として扱われますが、 ES5 ではこの仕様が変更されました。これによる などで、先頭が 0 で始まる文字列を変換するとき問題が生じます。先頭が 0 で始まる文字列は きますが、省略される場合が多いです。たとえば、フォームフィールドに入力されたデータの一部 parselnt() を使うと文字列を数値に変換できます。この関数の第 2 パラメータには基数を指定で 28 parselnt( ) による数値変換