Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

JSer Class #2

440 views

Published on

「JSer Class - JavaScriptの基礎と軽量フレームワーク」と題して職場で開催した勉強会の資料の第2回分。

Published in: Software
  • Be the first to comment

  • Be the first to like this

JSer Class #2

  1. 1. JSer Class JavaScriptの基礎と軽量フレームワーク
  2. 2. 目的 • 一般的観点 • Webアプリケーション開発のなかで存在感を増し続けるJavaScriptに ついて、「なんとなくわかる」でない知識を身に付ける。 • JavaScriptのメリット、デメリット、代替技術について知ることで、 保守/開発の生産性や品質を向上させる。 • 特殊的観点 • 数カ月後に身近な存在となる某クライアントサイドMVCライクなアプ リケーションの保守/開発のための基礎知識を得る。 再掲
  3. 3. 開催概要 • 開催日時 • 3/2(水)〜 毎週水曜 19:30〜21:30 全3回予定 • 会場 • コラボレーションスペース(N・W) • コンテンツ • 第1回 JavaScriptの言語仕様 • 第2回 DOMとXmlHttpRequest、軽量フレームワーク • 第3回 クライアントサイドMVC 再掲
  4. 4. 参考情報 • サイト • 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 再掲
  5. 5. JSer Class #2 DOM・XHR・軽量フレームワーク
  6. 6. 前回学んだこと • JavaScriptの基本型とオブジェクト型 • プロトタイプ・ベースのOOP • プロトタイプ・チェーンとスコープ・チェーン • そのどちらにも関わる関数オブジェクトの振る舞い
  7. 7. それが、何の役に立つの? • やや消極的な利点 • 「やってはならないこと」がわかる(主に開発向け) • 「〃」をやっているコードの臭いがわかる(主に保守向け) • 積極的な利点 • フレームワーク活用のための基礎知識 • 代替技術に手を伸ばすための足がかり いずれもJSの特性(プロトタイプ、ス コープ、関数オブジェクト、etc)を理 解することなしには、受動的利用にとど まり、生産性をあげることはできない。
  8. 8. イベントとリスナー
  9. 9. イベントとは何か? • 一般的な意味合い • アプリケーション・ユーザの画面操作や別システムからのデータ受信 など、何かしらプログラミング言語の世界の外からもたらされる「出 来事」。 • JavaScript固有の意味合い • Webページのロード(初期表示)、画面要素のクリック、フォームの フォーカスのON/OFF、入力値の変化、キーボードからの入力、 フォームの送信(submit)などユーザがWebブラウザ上で行ったアク ション(の情報)。
  10. 10. イベント・リスナーとは何か? • イベント発生時に起動される関数。 • リスナーはそれが生起する画面部品にあらかじめ登録しておく。 • 一般に(Javaの)匿名内部クラスに類する方法で実装される。 • 例: • ASP.NET: ユーザーコントロールに割当てられたdelegate • Swing: 画面部品に登録されたActionListener • Dalvik: 画面部品やサービスに登録されたEventListener • JavaScript: DOMノードに登録されたFunction • Akka(etc):Actorのreceiveメソッド ※かなり極端な例
  11. 11. ところで… • なぜリスナーは内部クラス(C#でいえばdelegate)で実装されるこ とが多いのだろうか? • イベントが起きる場所は、画面部品や通知サービス、リソース監視 サービスなど外界との境界面に位置する(=開発者が書いたコード 以外のどこか)。 • イベントが起きるタイミングは、ユーザのオペや何らかの情報の受 信、リソース状況の変化のときなど(=開発者が書いたコード以外 の何かが働いた時)。ようするに非mainスレッド上で起こる。 • 一方イベント発生時にしなくてはならないことは、アプリケーショ ンのプログラム・コードとして開発者が書いたもの。
  12. 12. リスナーの起動イメージ mainスレッド 画面部品 監視スレッド 通知監視/リソース監視サービス・スレッド UI ①アプリが起動しmain スレッドが実行される Service ②mainの処理で開発者 コードからリスナーが 登録される ④mainはここでアプリ が停止されるときまで 永遠に待機状態に入る③準備処理が完了 ⑤背後ではシステムに より自動で監視スレッ ドが起動される ⑥監視対象のイベント が起きるとこのスレッ ドからリスナーが起動 される ⑦×ボタンが押 された、サーバ がシャットダウ ンされた、etc.
  13. 13. リスナーの役割 • 内部クラスはそれが定義されたスコープに存在したオブジェク トへの参照を記憶している。 • Functionはそれが定義されたスコープに存在した変数への参照 を記憶している。 • リスナーが内部クラス(やdelegate)、Functionとして定義さ れることで、イベント発生の結果起こった「状態」の変化を記 憶し、他のリスナーと共有できる。 • もしこうした共有ができなければ、「項目にチェックを入れた あとボタン・クリック」とか「テキストを選択したあと右ク リック」といった状況をきちんと処理できない。
  14. 14. JavaScriptにおけるリスナー利用: 10年くらい前まで • HTMLのタグにonload、onclick、onfocusなどの属性を使って 関数名を指定して、リスナー関数として登録。 • 問題点: • 複数のリスナーを登録することができない。 • 動的なリスナーの登録/登録解除ができない。 • グローバル・スコープから参照できる名前でないといけない。 • コードが2つの世界(HTML vs JS)に散在する。
  15. 15. JavaScriptにおけるリスナー利用: 10年くらい前〜現在 • DOM(後述)のAPIを利用してリスナーを登録。 • 前述の問題点はすべて解消。 • 問題点: • ブラウザごとにAPIのインターフェースと挙動がまちまち。 • 「それぐらい標準で備わっていてよ」(頻繁に利用したい機能)が備 わってない。 ここでもIEは群を抜いて 「光って」いたが、一方で Safariもけっこうすごかった …。
  16. 16. いまはむかし • 「すごかった」内容を憶えて いないないし、思い出したく もない。 • なぜ過去形なのかは後述。 • あえて「すごさ」を知りたい 人にはこの本をおすすめしま す(*)。 * 『標準DOMスクリプティング』(http://www.amazon.co.jp/dp/4797336382) DOMってなに? は次スライド以降で 説明
  17. 17. サンプルコード // ドキュメント(=ページ)内からid="btn"要素を検索 var btnElm = document.getElementById("btn"); // 要素がクリックされたとき実行したい処理を関数として定義 var onClick = function () { alert('An element has id="btn" was clicked.'); }; // その関数をaddEventListenerメソッドで登録 btnElm.addEventListener("click", onClick); 当時、こんな素朴な処 理ですら、ブラウザ間 のAPIシグネチャのち がいなど諸々を克服す る必要があった。
  18. 18. DOM
  19. 19. DOMって何?の前に… • HTMLとは? • Webページを記述することを目的とするマークアップ言語。 • SGMLをベースとしている。 • JavaScript同様Webの黎明期から各ブラウザ・ベンダが各々実装。 • W3Cという標準化機関があとから仕様策定。 • 10年前(も今も)もっとも利用されているのはv4。 • XMLとは? • Webページ云々に限定されない汎用的なマークアップ言語。 • HTMLより曖昧性がすくない構文。 • W3Cが仕様策定。
  20. 20. DOMって何?の前に… • XHTMLとは? • HTMLのベースとSGMLからXMLに変更したもの。 • 10年まえにはこれがオーソリティを持っており、次期バージョンの仕 様策定や既存仕様を各社ブラウザがきちんと実装し終えることが熱望 されていた。 • HTML5とは? • 再度SGMLベースに戻ったマークアップ言語としてのHTMLの拡張と、 それに関連するJavaScriptのAPI拡張の仕様。
  21. 21. まあ、なんにせよ Webページのコンテンツを参照したり変更したりすること XML/HTMLを参照したり更新したりすること そのために利用されるAPIがDOM
  22. 22. DOMって何? • DOM:Document Object Modelの略。 • XML/HTMLドキュメントをプログラムコード(JavaやJS)か ら読み取り、探索し、変更するためのAPI仕様。 • W3CがLv1〜3まで段階的に策定をした。 • ドキュメントを木構造のオブジェクトで表わす。 • CSSやイベントに関する仕様も含まれ、Lvが上がるにつれてそ の傾向が強まる。 • XML/HTMLの仕様ではないし、XML/HTMLを操作するAPIの 唯一の仕様でもない(が、有名だし実際重要)。
  23. 23. DOMの構造 Document Element DocumentType Element Element Text CDATASection Attr Element Entity EntityReference Notation ProcessingInstructionDocumentFragment 木構造のルートは Documentノード Element=Tag 最重要のブランチ。 タグの入れ子構造を反 映した親子関係を持つ。 Attr=Attribute タグの属性をあらわす Commentほかにもいろいろある が、当面重要ではない
  24. 24. サンプルコード // ドキュメント(=ページ)内から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);
  25. 25. 参考資料 • 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の定めた仕様に起因 する使い勝手の悪さが際 立つ…(*)。
  26. 26. DOMの登場以前/以後 • DOM以前: • Webページの内容を動的に書き換える場合、document.write関数で新 しい内容を書き出すことしかできなかった。 • それもXML/HTMLとしてではなく単なる文字列として。 • DOM以後: • XML/HTMLを構成する要素(タグ)、属性、テキストをJavaScriptの オブジェクトとして生成、追加、変更、削除できるようになった。 • またそれらに紐付けられたCSS、イベント・リスナーも動的に操作す ることが可能になった。
  27. 27. 問題点 • 例によってブラウザごとに挙動がちがった。 • DOMの中でもHTML関連仕様の比重は大きいが、HTML専用の 仕様でないため、少々まどろっこしく、使い勝手が悪い。 そもそも仕様の記述 内容が曖昧なんです が…
  28. 28. XHR
  29. 29. XHRって何? • XmlHttpRequestというAPI名称の略。 • JavaScriptから任意のタイミングでWebサーバにコンテンツの リクエストを行うためのAPI。 • いわゆるAjaxの基盤。 • 「Xml」という枕が付いているがHTTPプロトコルでリクエス トできるものなら何でもリクエストできる。 • 同期通信/非同期通信はオプションで選べる。
  30. 30. なんでXHRが必要なの? • 「地図をドラッグすると隣接するエリアの情報が見られる」 「フォームの入力内容に応じてサジェストが表示される」など の機能を実現するには、「Webページ全体」ではなく「Web ページを構成する部品」を個別にロードする必要がある。 • こうしたリソース(HTML、XML、JSON、etc)の個別取得、 個別送信を可能にするのがXHR。
  31. 31. で、どんなふうに使うの? • わたしが教えてほしいくらい です(忘れた)。 • 知りたい人は「サイ本」を読 みましょう。 * 『JavaScript 第6版』(http://www.amazon.co.jp/dp/4873115736)
  32. 32. 共通する事項 • モダンなWebページ/Webアプリ作成には、イベント・リス ナー、DOM、XHRがほぼ必須となる。 • それらのいずれもブラウザごとに仕様の実装度合いがちがった り、明らかに仕様から逸脱しているケースが多かった。 ところで、なぜ「モダ ン」であって「テンポ ラリ」でないのか? 実のところ現在もそうした差 異は多いが、少なくとも「こ れは実験的機能です」と宣言 する程度に慎み深くなった。そうした背景のもと 登場したのが軽量FW
  33. 33. 重要なこと • JavaScriptでDOMやイベント・リスナーやXHRを直接利用する のは、Javaで(java.util.concurrentを使わず)Threadを直接利 用したり同期/並列コレクションを独自実装したりする以上に 危険で非生産的。 • なぜか? • 例えばJavaでは、ランタイムに問題があれば取り替えられる(Oracle、 IBM、Appleなどのベンダ製に加えOpenJDKも存在)。主導権は開発 者側にある。 • JavaScriptでは、問題があろうとなかろうと、すべてのブラウが潜在 的なランタイムであり、主導権は開発者側にない。 • APIの実装度合いや実装の正確さはブラウザごとにまちまち。よってそ の差異について現に詳しく、また今後も詳しくあり続けることなしに、 APIを直接利用してはならない。
  34. 34. 軽量フレームワーク
  35. 35. prototype.js • 単独で、あるいは組込みで、広範に利用され始めたJavaScript フレームワークの嚆矢。 • 機能/特徴: • クラス・ベースのOOPを模したオブジェクト定義API(DSL) • DOM/Event/XHRのブラウザ間差異吸収 • DOM APIの拡張と$・$$関数によるショートカットの提供 • Eventリスナの登録/解除を平易化するAPIの提供 • XHRをラップしたAjax APIの提供 • JSONの読み込み/書き出しの機能の提供 • UIのタテヨコや画面上の座標にアクセスするためのAPIの提供 • Arrayなど組込みオブジェクトのモンキーパッチ
  36. 36. prototype.jsには これ以上踏み込まない • prototype.jsの提供するAPIはそのほとんどがjQueryなど他のラ イブラリでも提供されている。そしてそのAPIはjQueryなど後 進のAPIと比べると使い勝手は劣る。 • しかもprototype.jsはモンキーパッチを多用しているので他の ライブラリとの併用にリスクがある(独自のJSランタイムを備 えるブラウザが1つ増えたイメージ)。 • したがって新規開発では使うべきではない。既存改修では慎重 に使うこと。
  37. 37. 余談)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>
  38. 38. 余談)prototype.jsとjQuery そしてグローバルスコープ • prototype.jsとjQueryはともに$という名前の変数をグローバ ル・スコープに定義し、関数を代入している。 • prototype.jsの$は引数の文字列をid属性値として扱い、DOM ノードを検索してそのノードそのもの(*)を返す。 • jQueryの$は引数の文字列をCSSセレクタ(**)として扱い、 DOMノードを検索してそのノード集合をラップした独自オブ ジェクトを返す。 • JavaScriptにはpackageもfinal変数(const定数/readonly変 数)も存在しない。よって後勝ちでprototype.jsの$は上書きさ れてしまい、それに依存したコードは破壊されてしまう。 * ただし例によってモンキーパッチが施されており、ブラウザ間差異を吸収する工夫がなされている。 ** 正確にいえばCSSセレクタを拡張したDSL。CSSセレクタにはできないこともできる。
  39. 39. 余談)prototype.jsとjQuery そしてグローバルスコープ • 2つのライブラリは併用されることが多かったので、紛争解決 策が用意されていた。 // $をprototype.jsの$に戻す jQuery.noConflict(); // $恋しい人のためのイディオム (function($) { // ここで$はjQueryの$を指している var x = $("foo"); ... })(jQuery); なぜ2つを併用するのか? 今から考えると無駄以外 の何ものでもないが、 Web開発は事ほど左様に 無秩序が支配する世界 だったということか…。 そして、それがかなら ずしも過去の問題では ないのが残念なところ。
  40. 40. jQuery • prototype.jsの次に来る、そしてさらに多くのユーザを勝ち得 たJavaScriptライブラリ。 • 機能/特徴: • prototype.jsと異なりクラス概念の模倣や標準APIの拡張はしない。 • DOM/XHR/Eventのブラウザ間差異吸収と生産性向上はさらに前進。 • とくに焦点をあてられているのはUI(≒DOM)の操作。 • アニメーションのためのAPIも持つ。 • アドイン機構を持ちユーザ(開発者)が独自の機能拡張を行いそれを 配布できるようになっていた点もおそらく人気の要因の1つ。
  41. 41. DOM vs. jQuery DOM • getterには「1要素 or null」 系メソッドと「0〜N要素」系 メソッドが用意されている。 • 言い換えれば、メソッドが返 すのはnull ot 要素オブジェク ト or 要素オブジェクト配列。 jQuery • 「0〜N要素」系メソッドのみ 用意されている。 • メソッドが返すのは「0〜N要 素」をあらわす集合オブジェ クト。 • 集合オブジェクトのメソッド を呼ぶことで「0〜N要素」す べてに効果が及ぶ。
  42. 42. jQueryオブジェクト • jQueryオブジェクトには0個 と1個とN個の区別がない。 • 0個の状態のオブジェクトに メソッド呼び出ししても実質 的には何も起こらないだけ。 • 反対に1〜N個の状態であれば 何かしらが起こる(はず)。 jQueryオブジェク トに内包された DOM要素(0〜N)
  43. 43. ノード探索① セレクタを利用したクエリ実行 • $(...)もしくはjQuery(...)関数を使用。 • 第1引数にはセレクタと呼ばれるDSLを指定する。 • 第2引数(省略可)には祖先ノードのDOM or jQueryを指定。 // 構文: $(selector) or $(selector, context) // fooというid属性を持つ要素を検索 var fooIdentified = $("#foo"); // foo配下でbarというclass属性を持つ要素を検索 var barClassifieds = $(".bar", fooIdentified);
  44. 44. セレクタの基本 • 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/)を参照のこと。
  45. 45. ノード探索② 親戚関係ベースの移動 • DOM同様、というかDOM以上に便利な、兄弟・子孫・祖先要 素へのアクセスを提供するメソッドが提供されている(*)。 • 例えば: • children() 子要素の集合を返す • prev() 1つ前の要素を返す • next() 1つ後の要素を返す • parent() 親要素を返す * 詳細については公式リファレンス(http://api.jquery.com/category/traversing/)もしくは有志の邦訳 (http://semooh.jp/jquery/api/traversing/)を参照のこと。 DOMとちがい、要素(タ グ)以外、コメントノード やテキストノード、CDATA ノードなどは眼中にない。
  46. 46. その他のノード操作API • 要素の追加を行う append/prepend/before/after/... • 属性アクセスを行う attr/addClass/css/... • 表示制御を行う show/hide/fadeIn/fadeOut/animate/... • リスナ設定を行う click/change/focus/... * 詳細については公式リファレンス(http://api.jquery.com/)もしくは有志の邦訳 (http://semooh.jp/jquery/)を参照のこと。
  47. 47. 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/)を参照のこと。
  48. 48. サンプル・アプリ • jQueryによるDOM操作、イベント・リスナー利用、Ajaxのサ ンプルとしてTODOアプリを用意した。 • サーバ側: • Java 7 EE • Spring Boot • Tomcat 7 • クライアント側 • HTML5 • jQuery 2.x • Bootstrap(CSSのみ) Spring Boot Cont- roller View Model Bootstrap jQuery HTML5
  49. 49. 起動方法 ① JDK 7以上のインストール ② Maven 3.xのインストール ③ コマンドプロンプトでプロジェクト・ディレクトリに移動 ④ mvn spring-boot:runコマンドを実行 ⑤ "Started SampleApplication in x.xxx seconds"という表示を 待つ ⑥ ブラウザでlocalhost:8080/index.htmlにアクセス
  50. 50. RESTful API URL メソッド 説明 /api/tasks GET タスク一覧の取得 /api/tasks/{id} GET タスクの取得 /api/tasks POST タスクの登録 /api/tasks/{id} DELETE タスクの削除
  51. 51. サンプル・アプリ解説①: ローカル・スコープ/ロード後の処理の定 義 (function($) { // 匿名関数により形成されたローカル・スコープ // 仮引数$は実引数jQueryを参照する // このコードはscriptタグのロードとともに実行される // ドキュメントの読み込みが終わった段階 // (loadイベント)で実行される関数を設定 $(document).ready(function() { // このコードはページロード完了時に実行される // (・・・省略・・・) }); })(jQuery);
  52. 52. サンプル・アプリ解説②: DOMノードの探索 // 主要なUI要素をクエリで検索し変数に格納 // テンプレートとなる要素 var taskTpl = $("tr.task-tpl"); // 新規タスク入力欄となる要素 var taskNew = $("tr.task-new"); // 新規タスク・タイトルの入力フォーム var taskNewTitle = $("input:text", taskNew); // 新規タスクの[+]ボタン var taskNewBtn = $("td.task-action > button", taskNew);
  53. 53. サンプル・アプリ解説③: イベント・リスナーの設定 // [+]ボタンにclickイベント・リスナーを設定 taskNewBtn.click(function (event) { // タイトル入力内容を取得 var title = taskNewTitle.val(); // タスク登録のための関数を実行 addTask({id: 0, title: title}); });
  54. 54. サンプル・アプリ解説④: 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);
  55. 55. サンプル・アプリ解説⑤: Ajaxによるリソース取得/送信 // 指定されたIDのタスクを削除する関数 var deleteTask = function(id) { // REST APIに対してDELETEメソッドで削除リクエストを送る $.ajax({ url: "/api/tasks/" + id, method: "DELETE", success: function (data, textStatus) { // APIがOKレスポンスを返したら一覧をリロード loadTasks(); } }); };
  56. 56. サンプル・アプリ解説⑥: バグはどこにある? $.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); } });
  57. 57. サンプル・アプリ解説⑥: バグはどう直す?(修正例) $.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); }); });
  58. 58. まとめ
  59. 59. 今回学んだこと • イベント・リスナー • DOM(Document Object Model) • XHR(Ajax) • 軽量フレームワーク(prototype.js/jQuery)
  60. 60. 次回は • 以下の項目について取り上げる予定: • クライアントサイドMVC • JavaScriptの代替技術

×