Comments
Description
Transcript
第4回付録 JavaScript
JavaScript 2015 年 10 月 6 日 この資料について: • ECMAScript の edition は 5 を想定 (最新は 5.1 Edition). • ECMA5 と書いた機能は Edition 5 のみ,何も書いてないものは Edition 3 と共通.余り信用しないこと. • 言語仕様 (第 4 回) とブラウザ依存部分 (第 5 回) を説明 • Java と似ているところは省略 • オブジェクト指向の説明はするが,これを直接使うことは余りない (普通は javascript ライブラリを使う) ので参考程度.この部分は現実のプログラミングとかなり違うかもしれない. • ブラウザ依存部分は少し詳しく説明する.DOM がどう JS から見えるか. • 以下においてページ数は,「JavaScript 第 6 版」(オライリージャパン) のもの • ie はまったく考えていない.Firefox が基本.たぶん Chrome も OK. • 【】はソースコードに関する説明. 自分でプログラムしてみるのが一番.src の jseval.html をデスクトップにコピーして,FireFox で開く. (Chrome はローカルなファイル内にある script タグは実行しない仕様なので,サーバーが必要かも.MyVolume が自分のホームページ作成に使える.) 超基本的なプログラミングの方法.html の中に, <script type="text/javascript"> JS プログラム </script> と書く.onload や onclick イベントを使って呼び出す. デバッグは,Chrome は,そのままで良い.FireFox もそのままで良いが,firebug という拡張機能は使いやす い.デバッグ画面を開く方法. • Firefox (標準): ツール→ Web 開発→ Web コンソール • Firefox (firebug): ツール→ Web 開発→ Firebug • Chrome: 設定→ツール→ JavaScript コンソール • MS Edge: 右上「他の操作」→ F12 開発者ツール このデバッグ画面にメッセージを表示するには,console.log(data); を実行する. 1 言語仕様 1.1 用語 プロパティ (property): オブジェクトを構成する,名前と値の組のこと アクセサプロパティ (accessor property): オブジェクトを構成する,名前と関数の組のこと.関数を通して値 1 にアクセスする. 内部プロパティ (internal property): 実装の都合上のプロパティで,直接アクセスできない. プロパティ属性 (property attribute または単に attribute): プロパティの性質 (Writable,Enumerable など がある).この資料では触れない. HTML 属性 (attribute): HTML 要素に対する性質の指定 1.2 数値 数値はすべて浮動少数点.ただし,ビット演算子のオペランドに現われた時は,整数にデータ表現変換をする. 1.3 文字列 ’ でも"でも良い.文字列はすべて immutable (書き換え不可).==は,中身の比較をする. 1.4 関数 関数もデータ. function f(x) { return x;} var f = function(x) { return x; } これは同じ意味になる.つまり,関数名と変数名は同じ名前空間.(厳密には変数 f のスコープが少し異なる.) 関数を呼び出すには,関数呼び出し,メソッド呼び出し,コンストラクタ呼び出し (2 章参照) という 3 つの方 法がある.(apply や call もある). 関数呼び出しは,f(); のような普通の書き方. あるオブジェクト (obj) のあるプロパティ (method) の値が関数とすると, obj.method(); このように書くとメソッド呼び出しとなる,this の値は obj になる.(なお,this は context object と呼ばれる.) しかし, var f = obj.method; f(); これは普通の関数呼び出しなので,this は obj ではない (グローバルオブジェクトになる). 【メモ 1】arguments 識別子を使うと,任意個の引数を受け取ることができる.arguments[i] のように書く.(な お,arguments は配列ではなく,Arguments オブジェクト.) 【メモ 2】関数型言語でクロージャと呼ばれる機能も入っている. function testclosure(){ var xxx=0; var f = function(){ return xxx++; } var g = function(){ return xxx++; } return [f,g]; } 関数ローカルな値を保持するもう一つの方法は, f.flocal = 0; function f(){ f.flocal++; ...} とやると関数に対して static な変数が宣言できる. 【メモ 3】動的に関数呼び出し式を作りたいときは,apply や call を使う.fn が関数とすると, 2 fn.apply(thisArg, args); ここで,thisArg は fn の中では this になる.args は配列. funcall もある.fn が関数とすると, fn.call(thisArg, arg1, arg2, ...); 1.5 オブジェクト オブジェクトとは,プロパティの集合である.プロパティとは,名前と値のペアである. {名前:値, 名前:値...} と書く. ●プロパティ ppp の参照 object.ppp object["ppp"] のどちらでも同じ. ●プロパティの追加 obj.newprop = value; とやれば,プロパティを追加できる. ●プロパティの削除 delete obj.prop; ●ゲッターとセッター (ECMA5) {プロパティ定義..., get x() {関数ボディ}, set x(value) {関数ボディ}, ...} とすることで,ゲッター x とセッター x を定義できる. object.x と書けば,x() が実行される. object.x = 10; と書けば,x(10) が実行される. ●その他 オブジェクト instanceof コンストラクタ これは,オブジェクトがあるクラス (風のもの) に属しているかの判定 (第 2 章). 1.6 配列 配列の生成は, var a = new Array(); 大きさは指定しなくても良いが,指定したいときは次のように書く. var a = new Array(10); Array の引数が 1 個で,それが数値のときだけ,サイズ指定になるという何とも言えない仕様. var a = new Array("a","b","c"); 3 とやれば初期値を入れることができる.これは次と同じ. var a = ["a","b","c"]; 連想と混在もできる.上に続けて, a["zzz"] = "abc"; とやっても良い.(ただし,a.length には反映されない.) なお, a[1]="a"; a[10000]="b"; とやっても,メモリを無駄使いすることはない. a.length=1; とやって,配列のお尻を削ることができる. a.length=10000; とやって,長くすることもできる.(たぶんメモリは取らない) 多次元配列はない.配列の配列を使う. 幾つかの特徴的なメソッド: concat(), slice(), splice(), shift() 配列要素とオブジェクトのプロパティは似ている.(特にプロパティの名前が数値の時は,どっちも a[1] などと アクセスできる.) しかし,length と連係動作するのは配列だけ.concat() などが使えるのも配列だけ. 配列の要素を全部見るときは,C のように for で添字を回して行けばよい.ECMA5 では,a.forEach(関数) のように回すこともできる. 1.7 特殊な値 null (0 や false への自動変換あり) undefined (宣言のみの変数の値,代入していない配列要素) 違うものだが,null==undefined (数値,文字列,真偽値の基本型には,Number, String, Boolean という名前のラッパークラスがある.) 1.8 変数 var で宣言する. 変数には型がない. 宣言なしにいきなり代入が可能.ただし,それが可能なのは大域変数だけ.(つまり,いきなり代入すると大域 変数とみなされる.) 実は変数は,あるオブジェクトのプロパティである. • 大域変数←グローバルオブジェクトのプロパティ • ローカル変数← Call オブジェクトのプロパティ function のネストが可能なので,変数のスコープもネストする.ブロック内変数はない.関数が呼ばれる と,Call オブジェクトが作られる.ローカル変数はこのオブジェクトにくっつくので,関数内はすべて有 効になる. • オブジェクトのプロパティは,obj.prop としてアクセスするしかない.メソッド内でも this.prop と書くし かない.prop とは書けない.(with を使うと書ける) 4 1.9 演算子 === これが Java や C の==に近い. オブジェクトは同一の時 true.基本データ型は値が同じ時 true.(文字列は中身を比較することに注意) == 型が同じ場合は===に同じ (?).一方,型が異なる場合は自動変換をする. – null==undefined は true, – 文字列==数値は,文字列を数値に変換して比較する. – オブジェクトは toString() する. typeof 基本データ型名 (”number”, ”string”, ”boolean”, ”object”等) を返す in obj が ppp というプロパティ名をもつかの判定."ppp" in obj のように書く. 1.10 文 switch 文 case には,任意の式が書ける.===で比較する. for/in 文 for (p in obj) ... obj のすべてのプロパティについて繰り返す.(これは,p=obj.property の形に変換されるので,p のところは var p とか,p[i] とか,代入式の左辺なら何でも良い.) もちろん,Java 風の for も書ける. throw 文,try/catch/finally 文 throw するのは何でも良いが,普通は,Error クラスのオブジェクト.Java のように catch を沢山は書けない. with 文 スコープチェーンの一時追加.自分で使うことは余りないが,ブラウザの実装としては重要.例えば,イベント ハンドラが実行されるスコープチェーンを考える.HTML がネストしているように,スコープチェーンもネスト し,イベントハンドラはそのレキシカルな環境下で実行される.これは with で説明すると分かりやすい. 2 プロトタイプ型オブジェクト指向計算 オブジェクトはプロパティの集合である.その他に幾つかの内部プロパティをもつが,最も重要なのは [[Prototype]] 内部プロパティである.以降では,単にプロトタイプと呼ぶ.オブジェクト obj のプロトタ イプは,Object.getPrototypeOf(obj) で入手できる (ECMA5).prototype という名のプロパティの値と [[Prototype]] 内部プロパティの値は,直接は関係ない. obj.prop という式を実行すると,まず obj がプロパティ prop をもつかを調べる.もしなければそのプロトタイプを探す. そのプロトタイプにも prop がない場合は,プロトタイプのプロトタイプを探す.このようにたらい回しにする動 作を委譲と呼ぶ.委譲先のオブジェクト (つまりプロトタイプ) がもつプロパティは,まるで委譲元のオブジェク トももっているように見える.このような委譲の仕組みで実現されたオブジェクト指向計算を,特にプロトタイ プ型オブジェクト指向計算と呼ぶ. なお,代入時は,上のような委譲はしないで this のプロパティに入る. 5 2.1 簡単なオブジェクトの生成 {x:1, y:2} と書くとオブジェクトが生成される.(実際のプログラムでこのように直接書き下すことはあまりない.) あるオブジェクトをプロトタイプとして,新たにオブジェクトを生成するには,次のように書く. Object.create(プロトタイプとなるオブジェクト); // 一般形 Object.create({x:1, y:2}); // 例 オブジェクトが作成され,そのプロトタイプは引数のオブジェクトとなる.(この時,prototype プロパティは作 られない.) 2.2 クラス風のプログラミングと new 次のように書くと,クラス風のプログラムができる. function Point(){ this.x=0; this.y=0; } Point.prototype.up = function(y){...}; // メソッド 1 Point.prototype.right = function(x){...}; // メソッド 2 インスタンスを作ってメソッドを呼んでみる. var c = new Point(); c.right(); 上の動作について説明する.まず,前述のように関数もオブジェクトである.オブジェクトなのでプロトタイ プをもつが,関数のプロトタイプは, {"constructor": その関数} という形をしたオブジェクトである.つまり,constructor プロパティをもつオブジェクトで,その値はその関 数自身である.また,関数は必ず prototype プロパティをもつ.その値はプロトタイプと同じ,つまり上で作っ た constructor だけのオブジェクトである. 次のような式を実行した時の動作を説明する. new 関数 () new が適用される対象の関数をコンストラクタと呼ぶ.これは特殊な関数ではなく,任意の関数である.上の式 を実行すると,イメージとしては次のような実行をしたことになる. this = Object.create(コンストラクタ.prototype); コンストラクタ.call(this); this の プ ロ ト タ イ プ は ,コ ン ス ト ラ ク タ の prototype プ ロ パ テ ィ の 値 で あ る が ,前 述 の よ う に こ れ は , constructor プロパティをもつオブジェクトである.コンストラクタの中では,this の初期化をする (そう するような関数を書く). this は最初はプロパティをもっておらず,コンストラクタの中で一つずつプロパティを 作る.これを図で表現すると,次のようになる. 6 コンストラクタ (Point) 共通のプロトタイプ constructor up() right() prototype * オブジェクト 1 オブジェクト 2 x:0 x:0 y:0 y:0 太矢印はプロトタイプ 細矢印はプロパティ @ I @ @ @ @ オブジェクト 3 @ x:0 y:0 以上のことより, var obj = new コンストラクタ (); によって生成された任意のオブジェクト obj は次のような性質をもつ. obj は,(委譲により) constructor プロパティを必ずもち,obj.constructor.prototype の値は,obj のプロ トタイプである.同じコンストラクタから作られたオブジェクトは,その constructor プロパティが同じなので, これを使って同じクラスに属しているかを判定できる.(obj は prototype プロパティはもたない.) なお,ここで prototype にプロパティをもたせてはいけない.つまり, Point.prototype.instvar=...; などとやると中途半端なクラス変数ができてしまう.特にプロパティを delete すると変なことになる.クラス変 数やクラスメソッドが必要なら次のようにする. function MyClass(){ this.instvar1=...; } MyClass.prototype.method1 = function(){...}; MyClass.prototype.method2 = function(){...}; MyClass.classvar1 = ...; MyClass.classmethod1 = function(){...}; 2.3 クラスの継承 クラスを継承したい時は,オブジェクトのプロトタイプのプロトタイプが親クラスになればよい.つまり,サ ブクラスの prototype に親のオブジェクトを入れればよい.次のようにすることで,Point のサブクラスである ColoredPoint を表現できる. function Point(){ this.x=... } function ColoredPoint(){ Point.call(this); this.color=... } ColoredPoint.prototype = new Point(); ColoredPoint.prototype.constructor = ColoredPoint; ColoredPoint.prototype.setColor = function(){...}; // 独自メソッドの追加 // delete ColoredPoint.prototype.instvar; // 継承したくない変数がある時 このプログラムを実行すると,次の図のようなデータ構造が生成される. 7 Point 共通のプロトタイプ constructor up() right() prototype - 太矢印はプロトタイプ 細矢印はプロパティ 6 ColoredPoint new Point() で作られたオブジェクト constructor setColor() * prototype オブジェクト 1 オブジェクト 2 x:0 x:0 y:0 y:0 color: color: @ I @ @ @ @ オブジェクト 3 @ x:0 y:0 color: あるオブジェクトのメソッドを呼び出すと,オブジェクトのプロトタイプを探し,そこになければ,更にそのプ ロトタイプを探して行く. 2.4 モジュールと名前空間 JavaScript 自身には名前空間の機能はない.オブジェクト毎のプロパティを利用して,名前空間風にするテク ニックや,関数内にローカルな関数を定義するテクニックがある.(p.191, p.267) 3 tips 3.1 書き方 HTML 内に書くときで,< や & が出現するときは,次のように書く. <script type="text/javascript"> <![CDATA[ ... ]]> </script> 普通 (defer がない時) は,出現する順番で script を実行する.また,イベントハンドラにも書ける (8 章を 参照). onclick, onousedown/up, onmouseover/out, onchange, onload/unload <script src="http://∼"></script> と書く時は,∼の先は javascript のプログラム (多くの場合,拡張子が.js) なので,そこは普通にプログラムを書 けば良い. 8 3.2 ブックマークレット URI の scheme に javascript:というのがある.URI を選んだときに,その場で javascript を実行できる. javascript:alert("JS executed!") ブックマークレットはこの応用.そのグローバル環境下で実行される. セキュリティのときにも説明するが,表示されているページの origin の中で何かを実行する唯一の方法がブッ クマークレットである.例えば Evernote や Tumblr などで使われている. 3.3 JSON シリアライズ (p.147) Web ペースのシステムにおいて,ホスト間でのデータ交換によく利用されるデータ表現形式に JSON と XML がある.後者については,11.2 を参照.JSON は,JavaScript Object Notation の略で,名前の通り JavaScript のオブジェクトを表現するための記法である.(2013 年 10 月,ECMA の標準規格 ECMA-404 として標準化さ れた.) JSON の例: 1 "abc" [3,10,20,4] {"foo": 3, "bar":"def"} ECMA5 では,オブジェクトと文字列の相互変換機能が用意された.まず,任意のオブジェクト o を文字列 s に するには,次のようにする. s = JSON.stringify(o); 逆に文字列 s をオブジェクト o に変換は次のように行う. o = JSON.parse(s); JSON を利用すると,異なるホスト間で JavaScript のオブジェクトを簡単に受け渡しできる.なお, o = eval(s); とやっても,多くの場合は JSON 文字列をオブジェクトに変換できる.eval は,文字列をプログラムとして解釈 実行する関数である.しかし,任意の文字列を直接 eval することは大変危険である.(ECMA3 でも,ライブラリ を使えば JSON.parse() が利用可能になるので,必ずこれを使う.) 現在では,JSON は RFC4627 で標準化されており,JavaScript でない言語 (例えば,ruby や perl) でも JSON 変換のライブラリが用意されている. 4 ブラウザ関連オブジェクト ブラウザ内の JS では,グローバルオブジェクトは window オブジェクトである.そのプロパティ (つまり大域 変数) の代表的なものを示す. window: ウィンドウ (window.window===window ということ) document: DOM のルート 9 location: 今参照している Web ページに関するオブジェクト location.host, location.href, location.pathname など history: ブラウザの履歴を操作するためのオブジェクト history.back(), history.forward() タイマー操作メソッド: setTimer(), setInterval() ウィンドウ操作メソッド: screenX,screenY ウィンドウの大きさ等 open() 新ウィンドウを開く 14.8 複数のウインドウとフレーム I303 フレームは図 1 のような関係になる. 図 14-3 フレ ーム聞 の相互関係 フレ ーム)自身は、横に並んだ 3つの サプフレ ームを持ち ます。 図 1 フレーム間の相互関係 (第 5 版の p.303 より引用) 1 4 . 8 . 2 ウインドウ名とフレーム名 先ほど紹介し た凶 i n d ow .o p e n()メソ ッ ドの 2番目の引数(省略可能)は、新たに生成するウインドウの名前で 利用者との対話 : す 。 HT MLの< f r a m e>タグでフレ ーム を生成するときに 、n a m e属性に名前を指定 で きま す。 これは非常に大切 confirm(), alert(), prompt() なこと です。 ウインドウ やフレー ムに名前を付け ておけば、< a >タグや < f o r m >タグ の t a r g e t属性にも、その 名前が使えるから です。ウ イン ドウ名 を指定する ことで、リンクをたと、 った結果やフオ ーム送信などの結果 5 ドキュメント関連オブジェクト (DOM) を表示する場所を ブラウザに 指示 できます。 一方 のウ インドウ名が t a b l eo fc o n t e n t s( 目次) で、他方のウインドウ名 例え ば 、 ウイ ンド ウが 2つあり、 JavaScript DOM の規格があり,それに対する バインディングという形で仕様が決まっている. がm a i n w i n( 主ウ インドウ ) で 、 t a b l eo fc o n t en tsウイン ドウに次の HTMLがある ものとします。 10 < ah r e f= 冗h a p te r 01 .h t m l "t a r g e t = "m ai n凶i n "> C h a pt e r1 ,I n t r o d u c t i o n< / a > document の重要なプロパティ cookie domain lastModified referrer title URL DOM の一般的な操作 • ノードは nodeType プロパティをもつ.これは数字で,ノードの種類を表す. • ノードの HTML 属性: getAttribute(), setAttribute() • 子は childNodes,親は parentNode. ここで childNodes は NodeList オブジェクトで,配列のようにアクセスできる.childNodes[1] など.(配 列ではないので length との連係はできない) その他,firstChild, lastChild, nextSibling, previousSibling • 子の操作は,appendChild(), removeChild(), replaceChild(), insertBefore() 各ノードは,基本的には,「HTML要素名Element」というクラスのオブジェクトになっている.例えば, HTMLBodyElement, HTMLDivElement など.HTML 属性は,基本的にはそのままの名前でプロパティになっ ている.例えば id.(簡単なダンププログラムを書けば中身をみられる.) 【 04/dumpobj.html.innerHTML の書き換えの例でもある.】 DOM オブジェクトの生成には,要素,テキスト (要素タグに挟まれた中のテキスト),HTML 属性の 3 つを 作る: e = document.createElement("div"); t = document.createTextNode("hogehoge"); e.appendChild(t); a = document.createAttribute("属性名"); a.nodeValue="値"; e.setAttributeNode(a); オブジェクト.appendChild(e); 要素の検索: document.getElementsByTagName("body") → 配列が返される document.getElementById("name") → その要素に対応するオブジェクト その他便利なもの: document.body は,body の一番上を指している.とても便利. innerHTML プロパティ window.getSelection().toString() セレクト状態のテキストを得る 【本の例 15-11 に DOM をいじるプログラムあり】 6 セキュリティ (p.363) 新しいウィンドウが作れるのは一部のイベントハンドラ (onclick) 内のみ.ユーザ操作に対応する形でしか作れ ないように制限している. FileUpload の value には JS から値を設定できない.任意のファイルのアップロードを防ぐため. 11 same origin policy domain プロパティを見て判断している. home.example.com を example.com に変更することはできる.com には変更できない. 7 CSS (p.449) 個々の要素オブジェクトを見つけて,style という HTML 属性をいじる. <div style="position: absolute; left: 100px; top:100px;"> というのは,次と等価. 要素オブジェクト.style.position="absolute"; 要素オブジェクト.style.left="100px"; 要素オブジェクト.style.top="100px"; もちろん,次も同じことになる. 要素オブジェクト.setAttribute("style", "position:absolute;top:100px;left:100px;") なお,style プロパティは CSSStyleDeclaration オブジェクトである.このうち重要そうなプロパティには,以 下がある. position, top, left, bottom, right, width, height, z-index, display, visibility, clip, overflow, margin, border, padding, background, opacity 各要素にはインラインスタイルで陽に指定したものだけが入る.スタイルシートで決めた値が,個々の要素の style にコピーされたりするわけではない.実際の見かけは,レンダリングエンジンが決めるが,それが個々の style プロパティに反映されたりはしないということ.なお,getComputedStyle() を使うと,見かけのスタイル を得ることができる. スタイルのプロパティ名は,ハイフンを除き,後の単語の先頭を大文字にする. font-family → fontFamily スタイルシートを操作することもできる.(16.5, 16.6 は略) 8 イベント (p.483) JavaScript の計算モデルは,非同期型,またはイベント駆動型と呼ばれる.プログラミングをしていて,一番 疲れるのがこの部分 (かもしれない).まず,実行はシングルスレッドであり,他の関数が並行して動作すること はない.従って,何かを待ちながら,別の仕事をすることはできない. しかし,実際は複数のユーザからの入力待ちをしたり,その裏で通信を行いたいことがある.JavaScript では, 何らかの事象が生じたときに,イベントを発生させることができる.イベント発生とその時に実行されるべき関 数 (この関数をイベントハンドラとかイベントリスナと呼ぶ.) を紐付けする機構があり,これを使って上記のよ うなプログラミングを可能にしている.ただし,イベントを受け付けるのは,今実行している関数がすべて終了し た時なので,何かを実行しながらイベントハンドラを実行できるわけではない. このプログラミングは非常に疲れるので,これを軽減するため,promise(9 章), yield (ES6 で導入) などが ある.) [イベント処理の詳細] (IE はかなり違う) 12 • ステップ 1 (capturing): ツリーを下りながらターゲットノードまでイベントが伝播して行く. • ステップ 2 (target): ターゲットノードでのイベント処理 • ステップ 3 (bubbling): ツリーを上にイベントが上がって行く. イベントハンドラの登録は: オブジェクト.addEventListener("イベント名", 関数, キャプチャハンドリング) 関数は 1 引数で,Event オブジェクトが渡される.(this は期待しない方が良い.) キャプチャハンドリン グが true の時はステップ 1 で,false の時はステップ 2 と 3 で呼ばれる.stopPropagation() (伝播の中止), preventDefault() (デフォルト動作の中止) ができる. もう少し手軽な書き方として,要素の HTML 属性で指定する方法もある. <div onclick="clicked();"> などのように書く.さらに別の書き方として, var dom = document.getElementById(∼); dom.onclick = function() {∼}; のような書き方もある.このような書き方をした場合は,戻り値が意味をもつ.false だと基本的にはエラーを意 味することになり,動作が停止する. 【少なくとも Firefox では,<div onclick="clicked();">とやっても,この div の onclick プロパティには 入らない.実際にクリックをすると,その時になって,addEventListener と onclick という 2 つのメソッドが追 加される.addEventListener の方が FireFox にとっては native ということ.onclick などはその上に実装されて いる. 】 IE では別の書き方になるので,詳細は省略. イベント処理は,フォームをリッチにするのに最も使われる.この例が 18 章にあるがこれも省略. 現在検討中の Pointer Events (http://www.w3.org/TR/pointerevents/) では,Mouse,Pen (タッチペン), Touch (パッド) 用にかなりイベントが増えている. 9 Promise Promise は正式には ECMAScript Version 6 からの導入であるが,同等のライブラリが既にある.Promise を 使うと,イベントハンドラーをきれいに記述できる. var p = new Promise(function(resolve, reject)∼); p.then(onResolveFn, onRejectFn); のように書く.promise オブジェクトを生成する際に,引数の関数が非同期に実行される.then は,その非同期 関数の実行が成功した時のハンドラと,失敗した時のハンドラの登録をする.当該非同期関数の中で成功や失敗 を promise に伝えるには,それぞれ resolve と reject を呼ぶ.典型的には,aSyncFn の中で例えば xhr を呼び, 成功なら resolve,失敗なら reject を呼ぶだけにする.本体の処理は,then の引数の関数に長々と書く. もし then によるハンドラの登録が遅れたとしても,ハンドラ呼び出しはペンディングされ,ハンドラが登録さ れた時点で一回だけ呼び出される. addEventListener の書き方は,長い処理の中でイベントが複数回生じる場合には自然である.一方,JavaScript のような非同期処理中心の言語では,一回だけ実行して,成功と失敗で処理を分けるという単純な流れを書きたい ことがある.Promise ではこれが自然に書ける. 13 10 クッキー (p.652) ・クッキーを JS で生成・削除できる. ・(4KB の) ローカルストアとしても使える. document.cookie = "名前=値; クッキー属性 1=値; クッキー属性 2=値; ..."; クッキー属性は, max-age=, expires=, path=, domain=, secure (ただし,document.cookie の中にクッキーの属性は見えない.) ”;” などが入った文字を cookie に入れるには,encodeURIComponent(), decodeURIComponent() を使う. 【→ 簡単なプログラムあり 04/cookie.html.cookie へは書き換えたいものだけを代入していることに注意. document.cookie=というのは単なる代入ではない.同じく参照も単に変数の値を見ているのではない.】 11 HTTP の制御 (p.535) 11.1 form の POST <form name="myform" action="http://..." method="post"> <input type= "text"> <input type="radio"> </form> submit を JavaScript で実行するには,次のようにする. document.myform.submit() 上の例では,myform を HTML で書いてあるが,createElement() で動的に作れば,どんなデータも submit できる. 11.2 XMLHttpRequest 【→ 05 ajax/xhr1.html】 Ajax のキモ!! var req = new XMLHttpRequest(); req.onreadystatechange = function(){ if (req.readyState==4 && req.status==200) { // 4: response received レスポンスのための処理 } }; req.open("GET", url, true); // 第 3 引数が true なら非同期 req.setRequestHeader("Accept-Language", "en"); // もし必要なら req.send(null); // ヘッダの後の空行 注 1: onreadystatechange のハンドラには,何も渡らないので,上記のようなスコープで実行するしかない. 14 注 2: same origin policy のため url は自分のサイトしか書けない. 注 3: タイムアウト等で中止する時は,req.abort() をする. 【→ xhr2.html のような書き方もできる.】 「レスポンスのための処理」の部分でよく使う書き方 • ヘッダの取得をしたいとき: req.getAllResponseHeaders() • レスポンスの文字列を取り出したいとき: req.responseText • レスポンスの MIME タイプが text/xml の場合: req.responseXML Content-Type ヘッダを調べて,”text/json”だったら,3.3 で述べたように,JSON.parse() を実行する. XML の時は,まず結果が XML か確認する: var type = req.getResponseHeader("Content-Type"); if (type.indexOf("xml") !== -1 && req.responseXML) ∼ みたいな感じ.次にパースして DOM にする: p = new DOMParser(); var x = p.parseFromString(text, "application/xml"); XML については第 7 回に取り上げる. 12 グラフィクス canvas (p.695) 【04/canvas.html】 3D グラフィクスについては,WebGL が標準化中である.中身は,OpenGL ES (Embedded System) を JavaScript から呼べるようにしたもの.ハードウェアを使って表示するので劇的に速い.Chrome と Firefox は 標準実装.Safari と Opera もあるらしい. 13 Version 5 以降の変更 この資料は ECMAScript version 5 に従っているが,既存の多くのプログラムは Version 3 で書いてある.改 めて,3 から 5 で追加された機能の主なものを挙げる. • strict mode が入った (宣言してない変数がエラーとなる等々) • JSON のパース • 配列メソッドの追加 (indexOf, every, some 等々) • Function.prototype.bind: this と arguments を束縛した関数を返す.event listener などグローバル環境 でしか動かないところに,メソッド (+this オブジェクト) を指定することができる. • 基本メソッドの追加.幾つかを下に示す.言語がきれいになった. keys メソッド: 継承でない独自プロパティの列挙 defineProperty メソッド: プロパティを作る.列挙不能なプロパティなど特殊なプロパティ属性を指定で きる. create メソッド: あるオブジェクトをプロトタイプとするオブジェクトの生成 freeze メソッド: オブジェクトの操作の禁止.他にも様々な禁止方法がある. (p.146) Version 6 は,現在標準化が進んでいる段階である.次のような多くの機能が入ると思われる. • Functions: 不定個引数関数,ラムダ式 (特に this の辺り) • Classes: 基本的には現在の prototype, constructor の syntax sugar.getter や setter などもある.継承も 15 簡単. • Collections: Set, Map, WeakMap.C の struct みたいな書き方も. • Iterators & Generators: Generator は yield を使ったコルーチン.非同期なプログラムも書きやすくなる. • Modules: モジュール機能が入った.export で宣言して import で利用. • Proxy: メソッドが存在しない時にハンドリングをする機構 • その他 (let によるブロック,Template 文字列等) 以下のページなども参照されたい. • http://www.slideshare.net/EyalV/whats-new-in-ecmascript-60 • http://es6-features.org/ • http://kangax.github.io/compat-table/es6/ 14 CommonJS ブラウザ以外で JavaScript を動かすための共通仕様を決めるプロジェクト (www.commonjs.org). CommonJS をフルスペックで実装したものはたぶん無い.しかし,Node.js など有名な実装も部分的に CommonJS を使っており,将来的にはこの仕様に収束して行く (ような気がする). 具体的には,Module,Package,JSGI,Promise などの API を決めている.また,次のような個々のモジュー ルについても決めている. • Binary data objects • Encodings • I/O streams • Filesystem • System interface • Unit Testing • Socket I/O • Reactor • Worker • console 例えば,この Module API を使うと,次のようにモジュール化できる. mymodule.js では, exports.fun = function(x) {∼}; と定義する.使う側では, var mod = require(’mymodule’); var fun = mod.fun; fun(1); などとして使う. 16