ExternalInterface周りのあれこれ
最近ECMAつながりでJavaScriptが気になって仕方ないです。 ExternalInterface APIの挙動というか実装が気なってあれこれ調べているのですが まだちょっとさわりしか触れていません。
ExternalInterfaceの実行されるタイミングが良く分からない
wonderflではExternalInterfaceが使えないので今回は使えませんが、検証例
navigateToURL(new URLRequest("javascript: alert('navigateToURL - second')"), "_self"); ExternalInterface.call("alert('ExternalInterface - first')");
下の行の方が先に実行されます。
ExternalInterface.callで返値が取れないこともある
リファレンスによると、再帰的な関数の返値が取れるかどうかは、ブラウザ依存ということらしいですが、 ExternalInterface.callにそのままJavaScriptのコードを渡した場合も取れないことがあるようです。 一般的に、navigateToURLとjavascript:の組み合わせの場合の方が、直感的に分かりやすい動きとなります。 ExternalInterface APIの方がブラウザ間の違いを吸収しているという風に書かれることもありますが、 僕自身ちょっとこのAPIの動きが今一掴めていないのでなんともいえません。
navigateToURL(new URLRequest("javascript: var bbb = function (x) { alert('in bbb');return x * x;};"), "_self"); ExternalInterface.call("alert", "start"); // start ExternalInterface.call("alert((function (x) {return x * x;})(17))"); // 289 ExternalInterface.call("function aaa () {alert('in aaa'); return x * x;}"); var ret = ExternalInterface.call("(function (x) {return x * x;})(18)") // 無名関数をその場で実行 ExternalInterface.call("alert", ret); // undefined ExternalInterface.call("alert", "calling aaa"); var aaa = ExternalInterface.call("aaa",19); // 上で定義した関数。呼ばれる環境とそうでない環境もある ExternalInterface.call("alert", "after calling aaa"); ExternalInterface.call("alert", aaa); // undefined いずれにせよ返値は取れない ExternalInterface.call("alert", "end"); // end ExternalInterface.call("alert", ExternalInterface.call("bbb", 100)); // 前述の通りこの時点ではnavigateToURLは評価されていないのでbbbは未定義 setTimeout(function () { // navigateToURLでjavascript:以降に定義した変数はあとでも使える ExternalInterface.call("alert", ExternalInterface.call("bbb", 100)); // 10000 ExternalInterface.call("alert(bbb)"); // function navigateToURL(new URLRequest("javascript: alert(bbb(20))"), "_self"); // 400 }, 500);
ExternalInterface APIのシリアライゼーション
ExternalInterfaceではJavaScriptとActionScriptの橋渡しをするときに一旦データを文字列でXMLの形式にシリアライズするのですが、 このシリアライゼーションはシンプルな実装なので、循環参照しているオブジェクトを渡すと、スタックオーバーフローが起こります。 また、同時に比較的コストが掛かるデータのやり取りなので瞬時に大量のデータをやり取りするのには向いていないと言えます。
var a:Object = {}; a.a = a; ExternalInterface.call("alert", a);
ExternalInterface今回はあんまり深く踏み込めませんでしたが、navigateToURLを使うと トップレベルにメソッドを生やすことが出来るということが分かりました。ちょっとだけ遊んでみましょう。
var scale:Number = 200; ti.text = "x * x"; btn.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void { navigateToURL(new URLRequest("javascript: var func = function (x) {" + "return " + ti.text + ";" + "}"), "_self"); setTimeout(draw, 200); }); btn.label = "draw"; function draw():void { var i:int = 1; graphics.clear(); graphics.lineStyle(1, 0xffffff); graphics.moveTo(0, calc(0)); while (i < stage.stageWidth) { graphics.lineTo(i, calc(i)); ++i; } }