練炭ブログ

萌え壁紙、Irvine、DMonkey、Proxomitron などの情報を扱ってます。

DMonkey: 数値リテラル

コメントなし»

数値リテラルの表記に誤りがあると通常は SyntaxError が発生しますが、一部のパターンではエラーにならず NaN として解釈されます。

alert (1e2x);   // NaN
alert (1e2.0);   // NaN

16進数リテラル 0x80000000 ~ 0xffffffff、0x8000000000000000 ~ 0xffffffffffffffff は負数になります。

0x0 ~ 0xffffffff は32ビット値を符号付き整数として、0x100000000 ~ 0xffffffffffffffff は64ビット値を符号付き整数として解釈しているのかもしれません。

alert (0x7fffffff);   // 2147483647
alert (0x80000000);   // -2147483648
alert (0xffffffff);   // -1
alert (0x100000000);   // 4294967296
alert (0x7fffffffffffffff);   // 9.22337203685478E18
alert (0x8000000000000000);   // -9.22337203685478E18
alert (0xffffffff00000000);   // -4294967296
alert (0xffffffffffffffff);   // -1

DMonkey: if/else ブロック内での関数定義

コメントなし»
(function () {
  alert (typeof foo + (typeof foo == 'undefined' ? '' : foo ()));
  if (true) {
    function foo () { return '#1'; }
  }
  else {
    function foo () { return '#2'; }
  }
  alert (typeof foo + (typeof foo == 'undefined' ? '' : foo ()));
}) ();
ブラウザ 1回目の alert 2回目の alert
IE function#2 function#2
Chrome function#2 function#2
Firefox undefined function#1
DMonkey undefined function#1

truefalse に変更した場合。

ブラウザ 1回目の alert 2回目の alert
IE function#2 function#2
Chrome function#2 function#2
Firefox undefined function#2
DMonkey undefined function#2

IE と Google Chrome は if/else ブロックのなかにあっても関数本体での定義として解釈され、後から記述した方(#2)が関数内全域で有効となります。

Firefox と DMonkey では、関数文が実行された時点でその関数(#1 または #2)が定義されます。

DMonkey: シフト演算子

コメントなし»

DMonkey のシフト演算子は JavaScript と異なります。

JavaScript DMonkey
<< 演算 符号なし左シフト
結果 -2147483648~2147483647
>> 演算 符号あり右シフト 符号なし右シフト
結果 -2147483648~2147483647 -2147483648~2147483647
>>> 演算 符号なし右シフト 符号なし右シフト
結果 0~4294967295 -2147483648~2147483647

見にくい表で申し訳ない。

今回は、シフトの際の符号の有無と演算結果を符号ありとなしのどちらとして解釈するかだけしか調べていません。それ以外で違うところもあるかも知れません。

DMonkey: ビット演算における小数の扱い

コメントなし»

JavaScript でビット演算のオペランドに小数を指定した場合、小数部を 0 方向に切り捨てて(round towards zero)、32ビットの整数に変換してから演算されます。

DMonkey では小数部を最近接偶数への丸め(round half to even)で整数化するため、演算結果が異なります。

alert (+1.5 | 0);   //  2 ※JavaSciprt では  1
alert (0 | -1.5);   // -2 ※JavaSciprt では -1

DMonkey: number.toExponential()

コメントなし»

number.toExponential ([digits])

Number オブジェクトのメソッド。
数を10進指数表記の文字列に変換します。

digits は小数部分の桁数を 1~17 で指定します(省略時は 1)。

丸めの方法は四捨五入で、負数は絶対値として丸めます(round half away from zero)。

JavaScript では digits を省略すると数を表現するのに必要な桁数として処理されますが、DMonkey では単に 1 が指定されたものとして動作します。

DMonkey: number.toFixed() / number.toPrecision()

コメントなし»

number.toFixed ([digits])

Number オブジェクトのメソッド。
数を10進固定小数点表記の文字列に変換します。

digits は小数部分の桁数を 0~18 で指定します(省略時は 0)。負数を指定すると整数部分を丸め、小数部分は18桁の '0' で埋められます。

丸めの方法は四捨五入で、負数は絶対値として丸めます(round half away from zero)。

数が 1e15 以上の場合は、digits の指定にかかわらず .toString() の結果と同じ文字列が返されます(多分)。

なお、alert (-1.25.toFixed (1)); で 0 と表示されるのは、number.toFixed の動作ではなく、

-1.25.toFixed (1)
= -(1.25.toFixed (1))
= -('1.3')
= -'1.3'

となり、-'1.3' は 0 になるという DMonkey の型変換の挙動の影響です(parseInt と同じ感じ)。

number.toPrecision ([digits])

JavaScript の number.toPrecision() は、有効数字を digits で指定した桁数に変更して文字列化するメソッドですが、DMonkey においてはそれとは異なり .toFixed() と同じ動作として実装されているようです。混乱防止のため、DMonkey においては .toPrecision() は一切使わない方がよいでしょう。

DMonkey: Math.round()

コメントなし»

JavaScript と DMonkey における Math.round() の動作の違い。

JavaScript …… round half up

  • 小数部分が 0.5 より大きければ、次に大きい整数。
  • 小数部分が 0.5 なら、次に大きい整数(↑と同じ)。
  • 小数部分が 0.5 より小さければ、次に小さい整数。

DMonkey …… round half to even

  • 小数部分が 0.5 より大きければ、次に大きい整数。
  • 小数部分が 0.5 なら、最近接偶数への丸め
  • 小数部分が 0.5 より小さければ、次に小さい整数。
function r (n) {
  alert ('Math.round (' + n + ') == ' + Math.round (n));
}

r (-2.5);   // -2
r (-1.5);   // -2
r (-0.5);   // 0
r (+0.5);   // 0
r (+1.5);   // 2
r (+2.5);   // 2

関連: DMonkey: Global.parseInt()

Global.parseInt() に number 型を渡した時も同じ丸め方になります。これらの挙動は Delphi の System.Round() を規定の丸めモード(rmNearest)で呼び出しているためと思われます。

DMonkey: iconv.dll による文字列変換

コメントなし»

KaoriYa さんが配布している Vim に同梱されている iconv.dll を使って、Irvine のスクリプトで UTF-8 文字列を Shift_JIS に変換するテスト。

function iconvUtf8ToSjis (text) {
	var Dorothy = { path: 'C:\bin\Irvine\Dorothy2\' };

	var dll = Dorothy.path + 'bin\iconv.dll';

	var d = new DynaCall ();
	d.register (dll, 'libiconv_open',	'i=ss',		'r=l');
	d.register (dll, 'libiconv_close',	'i=l',		'r=l');
	d.register (dll, 'libiconv',		'i=lssss',	'r=l');

	var n;

	var iconv = d.libiconv_open ('Shift_JIS//IGNORE', 'UTF-8');
	// alert ('libiconv_open: ' + iconv);

	var insb = new StringBuffer (text);
	var inbufp = new Struct ('inbuf:s');
	inbufp.inbuf = insb;

	var inbytesleftp = new Struct ('inbytesleft:l');
	inbytesleftp.inbytesleft = new Number (insb.length);

	var outsb = new StringBuffer (100);
	var outbufp = new Struct ('outbuf:s');
	outbufp.outbuf = outsb;

	var outbytesleftp = new Struct ('outbytesleft:l');
	outbytesleftp.outbytesleft = new Number (outsb.length);

	n = d.libiconv (iconv, inbufp, inbytesleftp, outbufp, outbytesleftp);
	// alert (n + "\n\n" + outbytesleftp.outbytesleft + "\n\n" + outsb.text);

	n = d.libiconv_close (iconv);
	// alert ('libiconv_close: ' + n);

	return outsb.text;
}

var t = String.fromCharCode (0x61, 0xF0, 0xA0, 0xAE, 0xB7, 0x7a);
alert (iconvUtf8ToSjis (t));

てきとうに書いたのでバッファの扱いとか間違っているかもしれません。Irvine の動作自体がおかしくなる恐れもあるので、このコードは実行しないで下さい。

変換できない文字を米印※とかゲタ〓のような任意の文字に変換できればよかったんですが、変換自体をエラーにするか文字を無視するかしか選べないようです。

DMonkey: オブジェクト.$数字 の直後に演算子を書くとエラー

コメントなし»
var o = { $1: 2 };
alert (o.$1+3);   // SyntaxError: Line(2) => Text( 3 )

オブジェクト.$数字 という形式の参照の直後に、スペースを置かずに +*
演算子を書くと SyntaxError になります。-/ は問題ありません。

上の例では alert (o.$1 +3) のようにスペースを入れると問題なく動作します。

RegExp.$1~$9 でもエラーになります。

DMonkey: URL オブジェクト

コメントなし»

DMonkey の new URL() で確保されるオブジェクトの挙動について。

url への書き込み
→ protocol username password hostname port path dir filename query に反映されます。

url からの読み込み
→ その時点の protocol username password hostname port path の値から URL が計算されて返されます。dir、filename、query の値は無視されます。

host への書き込み
→ hostname と、ポート番号があれば port に反映されます。

host からの読み込み
→ hostname と port の値から計算されて返されます。

protocol username password hostname port path directory filename query への書き込み
→ そのプロパティのみに反映されます。

上記プロパティからの読み込み
→ そのプロパティの値が返されます。

.toString()
→ 初期化時の URL または url プロパティへ書き込んだ URL が返されます。

上記に該当しない変化は起きません。

例えば、path を書き換えた後に filename を読み込んでも古い値のままです。
url の値を url へ書き込めば各プロパティにも反映されます。

var u = new URL ('http://example.com/aaa');
alert (u.filename);   // aaa

u.path = '/zzz';
alert (u.filename);   // aaa

u.url = u.url;
alert (u.filename);   // zzz

こういったプロパティごとの挙動の違いや、フラグメント識別子(#~)に対応していないところが使いづらく、ラッパーオブジェクトかあるいは完全に自前で処理するオブジェクトを作りたくなります。

ただ DMonkey では「プロパティを読み書きするとメソッドが呼ばれる」形での getter/setter が定義出来ないので、使いづらいのは解決できそうにないかなー。