60
JSer Class JavaScriptの基礎と軽量フレームワーク

JSer Class #2

Embed Size (px)

Citation preview

Page 1: JSer Class #2

JSer ClassJavaScriptの基礎と軽量フレームワーク

Page 2: JSer Class #2

目的

•一般的観点• Webアプリケーション開発のなかで存在感を増し続けるJavaScriptについて、「なんとなくわかる」でない知識を身に付ける。

• JavaScriptのメリット、デメリット、代替技術について知ることで、保守/開発の生産性や品質を向上させる。

•特殊的観点• 数カ月後に身近な存在となる某クライアントサイドMVCライクなアプリケーションの保守/開発のための基礎知識を得る。

再掲

Page 3: JSer Class #2

開催概要

•開催日時• 3/2(水)〜 毎週水曜 19:30〜21:30 全3回予定

•会場• コラボレーションスペース(N・W)

•コンテンツ• 第1回 JavaScriptの言語仕様

• 第2回 DOMとXmlHttpRequest、軽量フレームワーク

• 第3回 クライアントサイドMVC

再掲

Page 4: JSer Class #2

参考情報

•サイト• JavaScriptガイド@MDN

• https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide

•書籍• JavaScript 第6版(サイ本)

• http://www.amazon.co.jp/dp/4873115736

• Effective JavaScript• http://www.amazon.co.jp/dp/4798131113

再掲

Page 5: JSer Class #2

JSer Class #2 DOM・XHR・軽量フレームワーク

Page 6: JSer Class #2

前回学んだこと

• JavaScriptの基本型とオブジェクト型

•プロトタイプ・ベースのOOP

•プロトタイプ・チェーンとスコープ・チェーン

•そのどちらにも関わる関数オブジェクトの振る舞い

Page 7: JSer Class #2

それが、何の役に立つの?

•やや消極的な利点• 「やってはならないこと」がわかる(主に開発向け)

• 「〃」をやっているコードの臭いがわかる(主に保守向け)

•積極的な利点• フレームワーク活用のための基礎知識

• 代替技術に手を伸ばすための足がかり

いずれもJSの特性(プロトタイプ、スコープ、関数オブジェクト、etc)を理解することなしには、受動的利用にとどまり、生産性をあげることはできない。

Page 8: JSer Class #2

イベントとリスナー

Page 9: JSer Class #2

イベントとは何か?

•一般的な意味合い• アプリケーション・ユーザの画面操作や別システムからのデータ受信など、何かしらプログラミング言語の世界の外からもたらされる「出来事」。

• JavaScript固有の意味合い• Webページのロード(初期表示)、画面要素のクリック、フォームのフォーカスのON/OFF、入力値の変化、キーボードからの入力、フォームの送信(submit)などユーザがWebブラウザ上で行ったアクション(の情報)。

Page 10: JSer Class #2

イベント・リスナーとは何か?

•イベント発生時に起動される関数。

•リスナーはそれが生起する画面部品にあらかじめ登録しておく。

•一般に(Javaの)匿名内部クラスに類する方法で実装される。

•例:• ASP.NET: ユーザーコントロールに割当てられたdelegate

• Swing: 画面部品に登録されたActionListener

• Dalvik: 画面部品やサービスに登録されたEventListener

• JavaScript: DOMノードに登録されたFunction

• Akka(etc):Actorのreceiveメソッド ※かなり極端な例

Page 11: JSer Class #2

ところで…

• なぜリスナーは内部クラス(C#でいえばdelegate)で実装されることが多いのだろうか?

• イベントが起きる場所は、画面部品や通知サービス、リソース監視サービスなど外界との境界面に位置する(=開発者が書いたコード以外のどこか)。

• イベントが起きるタイミングは、ユーザのオペや何らかの情報の受信、リソース状況の変化のときなど(=開発者が書いたコード以外の何かが働いた時)。ようするに非mainスレッド上で起こる。

• 一方イベント発生時にしなくてはならないことは、アプリケーションのプログラム・コードとして開発者が書いたもの。

Page 12: JSer Class #2

リスナーの起動イメージ

mainスレッド

画面部品監視スレッド

通知監視/リソース監視サービス・スレッド

UI

①アプリが起動しmainスレッドが実行される

Service

②mainの処理で開発者コードからリスナーが登録される

④mainはここでアプリが停止されるときまで永遠に待機状態に入る③準備処理が完了

⑤背後ではシステムにより自動で監視スレッドが起動される

⑥監視対象のイベントが起きるとこのスレッドからリスナーが起動される

⑦×ボタンが押された、サーバがシャットダウンされた、etc.

Page 13: JSer Class #2

リスナーの役割

•内部クラスはそれが定義されたスコープに存在したオブジェクトへの参照を記憶している。

• Functionはそれが定義されたスコープに存在した変数への参照を記憶している。

•リスナーが内部クラス(やdelegate)、Functionとして定義されることで、イベント発生の結果起こった「状態」の変化を記憶し、他のリスナーと共有できる。

•もしこうした共有ができなければ、「項目にチェックを入れたあとボタン・クリック」とか「テキストを選択したあと右クリック」といった状況をきちんと処理できない。

Page 14: JSer Class #2

JavaScriptにおけるリスナー利用:10年くらい前まで• HTMLのタグにonload、onclick、onfocusなどの属性を使って関数名を指定して、リスナー関数として登録。

•問題点:• 複数のリスナーを登録することができない。

• 動的なリスナーの登録/登録解除ができない。

• グローバル・スコープから参照できる名前でないといけない。

• コードが2つの世界(HTML vs JS)に散在する。

Page 15: JSer Class #2

JavaScriptにおけるリスナー利用:10年くらい前〜現在• DOM(後述)のAPIを利用してリスナーを登録。

•前述の問題点はすべて解消。

•問題点:• ブラウザごとにAPIのインターフェースと挙動がまちまち。

• 「それぐらい標準で備わっていてよ」(頻繁に利用したい機能)が備わってない。

ここでもIEは群を抜いて「光って」いたが、一方で

Safariもけっこうすごかった…。

Page 16: JSer Class #2

いまはむかし

•「すごかった」内容を憶えていないないし、思い出したくもない。

•なぜ過去形なのかは後述。

•あえて「すごさ」を知りたい人にはこの本をおすすめします(*)。

*『標準DOMスクリプティング』(http://www.amazon.co.jp/dp/4797336382)

DOMってなに?は次スライド以降で

説明

Page 17: JSer Class #2

サンプルコード

// ドキュメント(=ページ)内からid="btn"要素を検索var btnElm = document.getElementById("btn");

// 要素がクリックされたとき実行したい処理を関数として定義var onClick = function () {

alert('An element has id="btn" was clicked.');

};

// その関数をaddEventListenerメソッドで登録btnElm.addEventListener("click", onClick);

当時、こんな素朴な処理ですら、ブラウザ間のAPIシグネチャのちがいなど諸々を克服する必要があった。

Page 18: JSer Class #2

DOM

Page 19: JSer Class #2

DOMって何?の前に…

• HTMLとは?• Webページを記述することを目的とするマークアップ言語。• SGMLをベースとしている。• JavaScript同様Webの黎明期から各ブラウザ・ベンダが各々実装。• W3Cという標準化機関があとから仕様策定。• 10年前(も今も)もっとも利用されているのはv4。

• XMLとは?• Webページ云々に限定されない汎用的なマークアップ言語。• HTMLより曖昧性がすくない構文。• W3Cが仕様策定。

Page 20: JSer Class #2

DOMって何?の前に…

• XHTMLとは?• HTMLのベースとSGMLからXMLに変更したもの。

• 10年まえにはこれがオーソリティを持っており、次期バージョンの仕様策定や既存仕様を各社ブラウザがきちんと実装し終えることが熱望されていた。

• HTML5とは?• 再度SGMLベースに戻ったマークアップ言語としてのHTMLの拡張と、それに関連するJavaScriptのAPI拡張の仕様。

Page 21: JSer Class #2

まあ、なんにせよ

Webページのコンテンツを参照したり変更したりすること

XML/HTMLを参照したり更新したりすること

そのために利用されるAPIがDOM

Page 22: JSer Class #2

DOMって何?

• DOM:Document Object Modelの略。

• XML/HTMLドキュメントをプログラムコード(JavaやJS)から読み取り、探索し、変更するためのAPI仕様。

• W3CがLv1〜3まで段階的に策定をした。

•ドキュメントを木構造のオブジェクトで表わす。

• CSSやイベントに関する仕様も含まれ、Lvが上がるにつれてその傾向が強まる。

• XML/HTMLの仕様ではないし、XML/HTMLを操作するAPIの唯一の仕様でもない(が、有名だし実際重要)。

Page 23: JSer Class #2

DOMの構造

Document

Element DocumentType

Element

Element

Text CDATASection Attr

ElementEntity EntityReference

Notation

ProcessingInstructionDocumentFragment

木構造のルートはDocumentノード

Element=Tag最重要のブランチ。タグの入れ子構造を反映した親子関係を持つ。

Attr=Attributeタグの属性をあらわす

Commentほかにもいろいろあるが、当面重要ではない

Page 24: JSer Class #2

サンプルコード

// ドキュメント(=ページ)内からh1要素を検索var h1Tags = document.getElementsByTagName("h1");

// h1タグで囲われた子孫ノードを文字列として取得var h1Cont = h1Tags[0].innerHTML;

// id属性をキーにして要素を検索var fooIdentified = document.getElementById("foo");

// fooの子要素の一覧から1番目(0開始)の要素を取得var fooChild1 = fooIdentified.childNodes[1];

// 新しい要素を作成var barCreated = document.createElement("bar");

// 要素をDOMのツリー内に追加するfooChild1.appendChild(barCreated);

Page 25: JSer Class #2

参考資料

• W3C - All Standards - DOM• https://www.w3.org/TR/#tr_DOM

•どら猫本舗 - DOM Lv1 仕様書の邦訳• http://www.doraneko.org/misc/dom10/19981001/cover.html

• Java SE同梱のDOM実装(W3C謹製)• https://docs.oracle.com/javase/jp/6/api/org/w3c/dom/package-

summary.html

* DOMのAPIの使い勝手を向上させるためにライブラリをつくってみました。プロジェクトのリポジトリはこちら→https://github.com/unclazz/unclazz-dom-queries

Java SE 1.4で追加された。W3Cの定めた仕様に起因する使い勝手の悪さが際

立つ…(*)。

Page 26: JSer Class #2

DOMの登場以前/以後

• DOM以前:• Webページの内容を動的に書き換える場合、document.write関数で新しい内容を書き出すことしかできなかった。

• それもXML/HTMLとしてではなく単なる文字列として。

• DOM以後:• XML/HTMLを構成する要素(タグ)、属性、テキストをJavaScriptのオブジェクトとして生成、追加、変更、削除できるようになった。

• またそれらに紐付けられたCSS、イベント・リスナーも動的に操作することが可能になった。

Page 27: JSer Class #2

問題点

•例によってブラウザごとに挙動がちがった。

• DOMの中でもHTML関連仕様の比重は大きいが、HTML専用の仕様でないため、少々まどろっこしく、使い勝手が悪い。

そもそも仕様の記述内容が曖昧なんです

が…

Page 28: JSer Class #2

XHR

Page 29: JSer Class #2

XHRって何?

• XmlHttpRequestというAPI名称の略。

• JavaScriptから任意のタイミングでWebサーバにコンテンツのリクエストを行うためのAPI。

•いわゆるAjaxの基盤。

•「Xml」という枕が付いているがHTTPプロトコルでリクエストできるものなら何でもリクエストできる。

•同期通信/非同期通信はオプションで選べる。

Page 30: JSer Class #2

なんでXHRが必要なの?

•「地図をドラッグすると隣接するエリアの情報が見られる」「フォームの入力内容に応じてサジェストが表示される」などの機能を実現するには、「Webページ全体」ではなく「Webページを構成する部品」を個別にロードする必要がある。

•こうしたリソース(HTML、XML、JSON、etc)の個別取得、個別送信を可能にするのがXHR。

Page 31: JSer Class #2

で、どんなふうに使うの?

•わたしが教えてほしいくらいです(忘れた)。

•知りたい人は「サイ本」を読みましょう。

*『JavaScript 第6版』(http://www.amazon.co.jp/dp/4873115736)

Page 32: JSer Class #2

共通する事項

•モダンなWebページ/Webアプリ作成には、イベント・リスナー、DOM、XHRがほぼ必須となる。

•それらのいずれもブラウザごとに仕様の実装度合いがちがったり、明らかに仕様から逸脱しているケースが多かった。

ところで、なぜ「モダン」であって「テンポラリ」でないのか?

実のところ現在もそうした差異は多いが、少なくとも「これは実験的機能です」と宣言する程度に慎み深くなった。そうした背景のもと

登場したのが軽量FW

Page 33: JSer Class #2

重要なこと

• JavaScriptでDOMやイベント・リスナーやXHRを直接利用するのは、Javaで(java.util.concurrentを使わず)Threadを直接利用したり同期/並列コレクションを独自実装したりする以上に危険で非生産的。

•なぜか?• 例えばJavaでは、ランタイムに問題があれば取り替えられる(Oracle、

IBM、Appleなどのベンダ製に加えOpenJDKも存在)。主導権は開発者側にある。

• JavaScriptでは、問題があろうとなかろうと、すべてのブラウが潜在的なランタイムであり、主導権は開発者側にない。

• APIの実装度合いや実装の正確さはブラウザごとにまちまち。よってその差異について現に詳しく、また今後も詳しくあり続けることなしに、APIを直接利用してはならない。

Page 34: JSer Class #2

軽量フレームワーク

Page 35: JSer Class #2

prototype.js

•単独で、あるいは組込みで、広範に利用され始めたJavaScriptフレームワークの嚆矢。

•機能/特徴:• クラス・ベースのOOPを模したオブジェクト定義API(DSL)• DOM/Event/XHRのブラウザ間差異吸収• DOM APIの拡張と$・$$関数によるショートカットの提供• Eventリスナの登録/解除を平易化するAPIの提供• XHRをラップしたAjax APIの提供• JSONの読み込み/書き出しの機能の提供• UIのタテヨコや画面上の座標にアクセスするためのAPIの提供• Arrayなど組込みオブジェクトのモンキーパッチ

Page 36: JSer Class #2

prototype.jsにはこれ以上踏み込まない• prototype.jsの提供するAPIはそのほとんどがjQueryなど他のライブラリでも提供されている。そしてそのAPIはjQueryなど後進のAPIと比べると使い勝手は劣る。

•しかもprototype.jsはモンキーパッチを多用しているので他のライブラリとの併用にリスクがある(独自のJSランタイムを備えるブラウザが1つ増えたイメージ)。

•したがって新規開発では使うべきではない。既存改修では慎重に使うこと。

Page 37: JSer Class #2

余談)prototype.jsとjQueryそしてグローバルスコープ// prototype.jsのJSファイルを読み込む<script type="text/javascript" src="prototype-x.x.x.js"></script>

// そのあとjQueryのJSファイルも読み込む<script type="text/javascript" src="jquery-x.x.x.js"></script>

<script type="text/javascript">

// "foo"という文字列を引数に$関数をコールvar x = $("foo");

// 得られたオブジェクトのinnerHTMLプロパティを参照var xInnerText = x.innerHTML;

// さて、なにが表示される?console.log(xInnerText);

</script>

Page 38: JSer Class #2

余談)prototype.jsとjQueryそしてグローバルスコープ• prototype.jsとjQueryはともに$という名前の変数をグローバル・スコープに定義し、関数を代入している。

• prototype.jsの$は引数の文字列をid属性値として扱い、DOMノードを検索してそのノードそのもの(*)を返す。

• jQueryの$は引数の文字列をCSSセレクタ(**)として扱い、DOMノードを検索してそのノード集合をラップした独自オブジェクトを返す。

• JavaScriptにはpackageもfinal変数(const定数/readonly変数)も存在しない。よって後勝ちでprototype.jsの$は上書きされてしまい、それに依存したコードは破壊されてしまう。

* ただし例によってモンキーパッチが施されており、ブラウザ間差異を吸収する工夫がなされている。** 正確にいえばCSSセレクタを拡張したDSL。CSSセレクタにはできないこともできる。

Page 39: JSer Class #2

余談)prototype.jsとjQueryそしてグローバルスコープ• 2つのライブラリは併用されることが多かったので、紛争解決策が用意されていた。

// $をprototype.jsの$に戻すjQuery.noConflict();

// $恋しい人のためのイディオム(function($) {

// ここで$はjQueryの$を指しているvar x = $("foo");

...

})(jQuery);

なぜ2つを併用するのか?今から考えると無駄以外の何ものでもないが、

Web開発は事ほど左様に無秩序が支配する世界だったということか…。

そして、それがかならずしも過去の問題ではないのが残念なところ。

Page 40: JSer Class #2

jQuery

• prototype.jsの次に来る、そしてさらに多くのユーザを勝ち得たJavaScriptライブラリ。

•機能/特徴:• prototype.jsと異なりクラス概念の模倣や標準APIの拡張はしない。

• DOM/XHR/Eventのブラウザ間差異吸収と生産性向上はさらに前進。

• とくに焦点をあてられているのはUI(≒DOM)の操作。

• アニメーションのためのAPIも持つ。

• アドイン機構を持ちユーザ(開発者)が独自の機能拡張を行いそれを配布できるようになっていた点もおそらく人気の要因の1つ。

Page 41: JSer Class #2

DOM vs. jQuery

DOM

• getterには「1要素 or null」系メソッドと「0〜N要素」系メソッドが用意されている。

•言い換えれば、メソッドが返すのはnull ot 要素オブジェクト or 要素オブジェクト配列。

jQuery

•「0〜N要素」系メソッドのみ用意されている。

•メソッドが返すのは「0〜N要素」をあらわす集合オブジェクト。

•集合オブジェクトのメソッドを呼ぶことで「0〜N要素」すべてに効果が及ぶ。

Page 42: JSer Class #2

jQueryオブジェクト

• jQueryオブジェクトには0個と1個とN個の区別がない。

• 0個の状態のオブジェクトにメソッド呼び出ししても実質的には何も起こらないだけ。

•反対に1〜N個の状態であれば何かしらが起こる(はず)。

jQueryオブジェクトに内包された

DOM要素(0〜N)

Page 43: JSer Class #2

ノード探索①セレクタを利用したクエリ実行• $(...)もしくはjQuery(...)関数を使用。

•第1引数にはセレクタと呼ばれるDSLを指定する。

•第2引数(省略可)には祖先ノードのDOM or jQueryを指定。

// 構文: $(selector) or $(selector, context)

// fooというid属性を持つ要素を検索var fooIdentified = $("#foo");

// foo配下でbarというclass属性を持つ要素を検索var barClassifieds = $(".bar", fooIdentified);

Page 44: JSer Class #2

セレクタの基本

• CSSのセレクタみたいなもの。でもそれ以上(*)。

•例えば:• #〜 id属性による要素指定

• .〜 class属性による要素指定

• [name=value] 任意属性による要素指定

• tagname タグ名による要素指定

• foo > bar fooの子要素bar

• foo bar fooの子孫要素bar

*詳細については公式リファレンス(http://api.jquery.com/category/selectors/)もしくは有志の邦訳(http://semooh.jp/jquery/api/selectors/)を参照のこと。

Page 45: JSer Class #2

ノード探索②親戚関係ベースの移動• DOM同様、というかDOM以上に便利な、兄弟・子孫・祖先要素へのアクセスを提供するメソッドが提供されている(*)。

•例えば:• children() 子要素の集合を返す

• prev() 1つ前の要素を返す

• next() 1つ後の要素を返す

• parent() 親要素を返す

*詳細については公式リファレンス(http://api.jquery.com/category/traversing/)もしくは有志の邦訳(http://semooh.jp/jquery/api/traversing/)を参照のこと。

DOMとちがい、要素(タグ)以外、コメントノードやテキストノード、CDATAノードなどは眼中にない。

Page 46: JSer Class #2

その他のノード操作API

•要素の追加を行う append/prepend/before/after/...

•属性アクセスを行う attr/addClass/css/...

•表示制御を行う show/hide/fadeIn/fadeOut/animate/...

•リスナ設定を行う click/change/focus/...

*詳細については公式リファレンス(http://api.jquery.com/)もしくは有志の邦訳(http://semooh.jp/jquery/)を参照のこと。

Page 47: JSer Class #2

AjaxのためのAPI(例)

• jQuery.ajax(options)• リクエスト先URLや送信データのほか、同期/非同期、キャッシュ利用の有無、データ形式など種々のオプションを指定して通信を実施。

• jQuery.get(url, data, callback)• URLと送信データ、リクエスト成功時のコールバック関数だけを指定して、GETメソッドのリクエストを送る。

• jQuery.post(url, data, callback)• URLと送信データ、リクエスト成功時のコールバック関数だけを指定して、POSTメソッドでリクエストを送る。

*詳細については公式リファレンス(http://api.jquery.com/)もしくは有志の邦訳(http://semooh.jp/jquery/)を参照のこと。

Page 48: JSer Class #2

サンプル・アプリ

•jQueryによるDOM操作、イベント・リスナー利用、AjaxのサンプルとしてTODOアプリを用意した。

•サーバ側:• Java 7 EE

• Spring Boot

• Tomcat 7

•クライアント側• HTML5

• jQuery 2.x

• Bootstrap(CSSのみ)

Spring Boot

Cont-roller

View

ModelBootstrap

jQuery

HTML5

Page 49: JSer Class #2

起動方法

① JDK 7以上のインストール

② Maven 3.xのインストール

③ コマンドプロンプトでプロジェクト・ディレクトリに移動

④ mvn spring-boot:runコマンドを実行

⑤ "Started SampleApplication in x.xxx seconds"という表示を待つ

⑥ ブラウザでlocalhost:8080/index.htmlにアクセス

Page 50: JSer Class #2

RESTful API

URL メソッド 説明

/api/tasks GET タスク一覧の取得

/api/tasks/{id} GET タスクの取得

/api/tasks POST タスクの登録

/api/tasks/{id} DELETE タスクの削除

Page 51: JSer Class #2

サンプル・アプリ解説①:ローカル・スコープ/ロード後の処理の定義(function($) {

// 匿名関数により形成されたローカル・スコープ// 仮引数$は実引数jQueryを参照する// このコードはscriptタグのロードとともに実行される

// ドキュメントの読み込みが終わった段階// (loadイベント)で実行される関数を設定$(document).ready(function() {

// このコードはページロード完了時に実行される// (・・・省略・・・)

});

})(jQuery);

Page 52: JSer Class #2

サンプル・アプリ解説②:DOMノードの探索// 主要なUI要素をクエリで検索し変数に格納// テンプレートとなる要素var taskTpl = $("tr.task-tpl");

// 新規タスク入力欄となる要素var taskNew = $("tr.task-new");

// 新規タスク・タイトルの入力フォームvar taskNewTitle = $("input:text", taskNew);

// 新規タスクの[+]ボタンvar taskNewBtn = $("td.task-action > button", taskNew);

Page 53: JSer Class #2

サンプル・アプリ解説③:イベント・リスナーの設定// [+]ボタンにclickイベント・リスナーを設定taskNewBtn.click(function (event) {

// タイトル入力内容を取得var title = taskNewTitle.val();

// タスク登録のための関数を実行addTask({id: 0, title: title});

});

Page 54: JSer Class #2

サンプル・アプリ解説④:DOMノードの追加/更新/削除// タスク一覧をクリアする$("tr.task-item").remove();

(・・・省略・・・)

// テンプレートをクローンするvar taskItem = taskTpl.clone().show();

// テンプレ用のclass属性を削除し、表示項目用のclass属性を追加taskItem.removeClass("task-tpl").addClass("task-item");

// 子孫ノードから#列に該当する要素を検索しタスクIDを設定$("td.task-id", taskItem).text(item.id);

(・・・省略・・・)// 種々設定済みの要素を新規タスク入力欄の「手前」に追加taskNew.before(taskItem);

Page 55: JSer Class #2

サンプル・アプリ解説⑤:Ajaxによるリソース取得/送信// 指定されたIDのタスクを削除する関数var deleteTask = function(id) {

// REST APIに対してDELETEメソッドで削除リクエストを送る$.ajax({

url: "/api/tasks/" + id,

method: "DELETE",

success: function (data, textStatus) {

// APIがOKレスポンスを返したら一覧をリロードloadTasks();

}

});

};

Page 56: JSer Class #2

サンプル・アプリ解説⑥:バグはどこにある?$.get("/api/tasks", {}, function(data) {

var key, item;

for (key in data) {

item = data[key];

var taskItem = taskTpl.clone().show();

taskItem.removeClass("task-tpl").addClass("task-item");

$("td.task-id", taskItem).text(item.id);

$("td.task-title", taskItem).text(item.title);

$("td.task-action > button", taskItem).click(function(event) {

deleteTask(item.id);

});

taskNew.before(taskItem);

}

});

Page 57: JSer Class #2

サンプル・アプリ解説⑥:バグはどう直す?(修正例)$.get("/api/tasks", {}, function(data) {

$.each(data, function(index, item) {

var taskItem = taskTpl.clone().show();

taskItem.removeClass("task-tpl").addClass("task-item");

$("td.task-id", taskItem).text(item.id);

$("td.task-title", taskItem).text(item.title);

$("td.task-action > button", taskItem).click(function() {

deleteTask(item.id);

});

taskNew.before(taskItem);

});

});

Page 58: JSer Class #2

まとめ

Page 59: JSer Class #2

今回学んだこと

•イベント・リスナー

• DOM(Document Object Model)

• XHR(Ajax)

•軽量フレームワーク(prototype.js/jQuery)

Page 60: JSer Class #2

次回は

•以下の項目について取り上げる予定:• クライアントサイドMVC

• JavaScriptの代替技術