300 likes | 450 Vues
JavaScript Programming 2.0. 伊藤 直也 naoya@hatena.ne.jp 株式会社はてな http://www.hatena.ne.jp/ 2005.08.26. アジェンダ. なぜいま JavaScript? JavaScript で OO 最近熱い JavaScript な技術. なぜいま JavaScript?. ユーザーインタフェースプログラミング DHTML Ajax Remix user script (Greasemonkey, Turnabout etc) プラットフォーム ( ブラウザ ) の進化
E N D
JavaScript Programming 2.0 伊藤 直也 naoya@hatena.ne.jp 株式会社はてな http://www.hatena.ne.jp/ 2005.08.26
アジェンダ • なぜいま JavaScript? • JavaScript で OO • 最近熱いJavaScriptな技術
なぜいまJavaScript? • ユーザーインタフェースプログラミング • DHTML • Ajax • Remix • user script (Greasemonkey, Turnabout etc) • プラットフォーム(ブラウザ)の進化 • Firefox / Safari / Opera / IE 7 JavaScript Programming 再評価 (= 2.0) な2005年
JavaScript で OO • JavaScript でも OO できるよ • プロトタイプベースなOO言語 • いろいろ奥深い • Javaとかはクラスベース • 関数がオブジェクト • モテも非モテも可 • 手続き型で泥臭く … JavaScript Programming 1.0 • OO でかっこよく? … JavaScript Programming 2.0
関数がオブジェクト • 関数もオブジェクト。関数がオブジェクトの素 /* コンストラクタ */ function Dog (name) { this.name = name; } var dog = new Dog(‘しなもん’); document.writeln(dog.name);
メソッド追加はプロパティへの代入 • プロパティに関数を代入でメソッド完成 function Dog (name) { this.name = name; this.bark = bark; } function bark () { document.writeln(this.name + ‘: わん’); } var dog = new Dog(‘しなもん’); dog.bark();
メソッド追加はプロパティへの代入なので… • インスタンスに直接メソッドを追加できる var dog = new Dog(‘しなもん’); dog.bark = function() { ... }; dog.bark(); • イベントハンドラへの登録でやってる /* document の onload プロパティに代入 */ document.onload = function () { ... };
prototypeオブジェクト • その関数をインスタンス化した場合のインスタンス参照 (つまりプロトタイプ) • これに色々代入することでオブジェクトを作っていく (プロトタイプベースOO) • ので、インスタンスの振る舞いは後から幾らでも拡張/変更できる function Dog (name) { this.name = name; } Dog.prototype.bark = function() { ... }; Dog.prototype.foo = function() { ... }; Dog.prototype.bar = function () { ... }; var dog = new Dog('しなもん'); dog.bark(); dog.foo(); dog.bar();
Objectオブジェクト • すべてのオブジェクトの祖先 • for/in でプロパティをほげる。 • 連想配列代わりにも使える var object = new Object(); object.jkondo = 'Junya Kondo'; Var hash = new Object(); hash[‘naoya’] = 'Naoya Ito'; hash[‘kawasaki’] = 'Yuichi Kawasaki'; for (var id in hash) { document.write(hash[id]); }
継承(っぽいの) // スーパークラス function Human(name) { this.name = name; } // サブクラス function Programmer(name) { this.base = Human; this.base(name); } Programmer.prototype.programming = function () { document.writeln(this.name + ' 「コードを書くよ」'); } // さらに継承 function PerlProgrammer(name) { this.base = Programmer; this.base(name); } // オーバーライドっぽいの PerlProgrammer.prototype.programming = function () { Programmer.prototype.programming.apply(this);// super(); document.writeln(this.name + ': 「#!/usr/local/bin/perl」'); }
prototype.js で OO • Ajax とか Class-Style OO とかの JavaScript フレームワーク • http://prototype.conio.net/ • クラスベースの方がコードが分かりやすい(かも)。 • prototype.js の Class と Object.extend() の出番
Class / Object.extend() • prototype.js で JavaScript でクラスライクOO // in html <script type=“text/javascript” src=“/path/to/prototype.js”></script> // in js /* class Animal */ var Animal = Class.create(); Animal.prototype = { initialize : function (name) { this.name = name; }, bark : function () { document.writeln(this.name); } } /* class Dog */ var Dog = Class.create(); Dog.prototype = (new Animal).extend({ bark : function() { Animal.prototype.bark.apply(this); } });
prototype.jsでデザインパターン • やってみてます • http://d.hatena.ne.jp/naoya/20050813 • 結城さん本万歳! / ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ | ほう、Abstract Factoryパターンですか?\  ̄ ̄ ̄|/ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ∧_∧ / ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ( ・∀・) ∧ ∧ < な、なんですか?あなた・・・ ( ⊃ ) (゚Д゚;) \____________  ̄ ̄ ̄ ̄ ̄ (つ_つ____  ̄ ̄ ̄日∇ ̄\|ThinkPad|\  ̄ ========= \
例: Iteratorパターン var Book = Class.create(); Book.prototype = { initialize : function(name) { this.name = name; }, getName : function() { return this.name; } } var BookShelf = Class.create(); BookShelf.prototype = { initialize : function() { this.last = 0; this.books = new Array(); }, getBookAt : function(index) { return this.books[index]; }, appendBook : function(book) { this.books[this.last] = book; this.last++; }, getLength : function() { return this.last; }, iterator : function() { return new BookShelfIterator(this); } } var BookShelfIterator = Class.create(); BookShelfIterator.prototype = { initialize : function(bookshelf) { this.bookshelf = bookshelf; this.index = 0; }, hasNext : function () return this.index < this.bookshelf.getLength(); }, next : function() { return this.bookshelf.getBookAt(this.index++); } }
Ajax - Asynchronous JavaScript + XML • もはやおなじみの動的ロードテクニック • XMLHttpRequest で非同期通信
Ajax の構成技術 クライアント側 サーバー側 HTML + CSS ブラウザ描写(DHTML) サーバーサイド アプリケーション DOM JavaScript XMLHttpRequest 非同期通信 XML API
DHTML Ajax • XMLHttpRequest + DHTML + (XML) var request = new XMLHttpRequest(); request.open("GET", "hello.txt", true); request.onreadystatechange = function() { if (request.readyState == 4) { document.getElementById('message').innerHTML = request.responseText; // or responseXML } } request.send(null); この手の処理を イベントハンドラに 登録する
CSI - Client Side Inclusion • 外のサイトにある js をクライアントでロード • くっつき系。 • HTMLにRSS貼ったりとか。 • BlogPet とか。 • 一歩進めて、ライブラリ/実行環境を読み込む手段として • Google AdSense • Google Maps API • JSON feed <script type=“text/javascript” src=http://example.com/js/foo.js></script>
Google Maps API • CSI なライブラリによるAPI • JavaScriptプログラミングでGoogle Maps使えるYO! • GXmlHttp で Ajax りつつサーバーサイドアプリケーションと連携 • Hatena::Map <html> <head> <!-- CSI で API ライブラリ読み込み --> <script src="http://maps.google.com/maps?file=api&v=1&key=..." type="text/javascript"></script> </head> <body> <!-- Google Maps API が DHTML で描写されるエレメント --> <div id="map" style="width: 500px; height: 400px"></div> <!-- Hack! --> <script type="text/javascript"> var map = new GMap(document.getElementById("map")); map.addControl(new GSmallMapControl()); map.centerAndZoom(new GPoint(139.70486, 35.65497), 2); ... </script> </body> </html>
JSON – JavaScript Object Notation • データ交換フォーマット • JavaScriptの記法でオブジェクト、データ構造をシリアライズ • Matz日記曰く「YAMLみたいなもの」 • PerlのData::Dumper みたいな感じ • 変数として受け取るとか eval で受けるとかしてでデシリアライズ starwars.jedi.skywalker[0] = 'anakin'; starwars.jedi.skywalker[1] = 'luke'; var starwars = { jedi : { skywalker : [ 'anakin', 'luke' ] } }
JSON.pm – Perl to JSON • Perlのデータ構造を JSON に変換 • Ajaxで使うとベンリ #!/usr/local/bin/perl use strict; use JSON; my $starwars = { jedi => { skywalker => [ 'anakin', 'jedi' ], }, }; my $js = JSON->new->objToJson($starwars, { pretty => 1, indent => 2, }); print $js; { "jedi" : { "skywalker" : [ "anakin", "jedi" ] } }
XML::Simple + JSON で Ajax • [Perl] XML over HTTP な API を叩く • [Perl] XML::Simple で parse • [Perl] そのまま objToJson で変換 • [JavaScript] XMLHttpRequest で結果取得 • [JavaScript] JSON を eval • [JavaScript] 復元したデータで DHTML DBからデータを読み出してPerlな構造にした後、 JSON に変換して JavaScript に渡すとか色々応用できる。
JSON feed • del.icio.us - フィードをJSONで表現 • JavaScript + Web で直接 Hack できるように • RSS だとサーバーサイドプログラムが必要になりがち • CSI で JSON を Include して Hack • http://del.icio.us/doc/feeds/json/ <script type="text/javascript" src="http://del.icio.us/feeds/json/lukeskywalker?count=20"></script> <script type="text/javascript"> var ul = document.createElement('ul'); for (var i = 0, post; post = Delicious.posts[i]; i++) { ... document.createElement('a'); a.setAttribute('href', post.u); a.appendChild(document.createTextNode(post.d)); ... } document.getElementById('container').appendChild(ul);
JKL.ParseXML • XMLをJSONに展開するクラス • http://www.kawa.net/works/js/jkl/parsexml.html • Ajax でのしんどいXML DOMとおさらば <script type="text/javascript" src="jkl-parsexml.js"></script> <script type="text/javascript"> var parser = new JKL.parseXML('http://example.com/starwarsapi'); var starwars = parser.parse(); document.write(starwars.jedi.skywalker[0]); // anakin </script>
JSAN – JavaScript Archive Network • JavaScript版CPAN • Perl の JSAN.pm (JSAN shell)でインストール • CPANに同じく色々ある • prototype.js から切り出されたもの • Class • Object.extend • Function.bind • Form.Validator • Form.Serializer • Wikiwig • DOM.Triggers • Debug.logger
JavaScript 開発 & デバッグ • http://www.hatena.ne.jp/1123227040 • objectdump.js • Venkhman • ecma-script-mode.el
ブラウザを Hack する • ブラウザを Hack する手段としての JavaScript • Bookmarklet • user script • Greasemonkey, Trixie, Turnabout ...
まとめ • JavaScript を正しく評価しよう • Web 1.0 な JavaScript の先入観は捨てよう • 悪い例による盲目 • JavaScriptでできることを"手段"として身に着けよう • サーバーサイドアプリケーションとの連携 • ブラウザ Hack、ユーザーインタフェースPG