練炭ブログ

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

DMonkey: .call()/.apply() の挙動

コメントなし»

Property Accessors (関数オブジェクト以外は省略)

関数オブジェクト . プロパティ名

プロパティ名は prototypecallapply のみ使用できる。

call は関数オブジェクトの動作モードを fcfCall モードに変更し、関数オブジェクト自身を返す。

apply は関数オブジェクトの動作モードを fcfApply モードに変更し、関数オブジェクト自身を返す。

fcfCall モードの関数オブジェクトに対し .apply 演算を行うと fcfApply モードに変更される。逆も同じ。

function a () { }
alert (a === a.call);  // true

function b () { }
alert (b === b.apply);  // true

function c () { }
alert (c.call === c.apply);  // true
alert (c.call.apply.call.apply === c.apply.call.apply.call);  // true

関数オブジェクトを通常モードに戻す手段は、恐らくない。

なお、Bracket notation のつもりで

関数オブジェクト [ "call" ]

と書くと DMonkey の言語仕様により "call" を引数とした関数呼び出しが行われてしまうので、Dot notation でしかアクセスできない。

関数呼び出し

( ) (または [ ])

fcfCall モードの関数を引数付きで呼び出すと .call() の動作が実行される(第1引数が this、あれば第2引数以降が arguments)。

fcfApply モードの関数を引数付きで呼び出すと .apply() の動作が実行される(第1引数が this、あれば第2引数の配列が arguments)。

それ以外、つまり通常モードの関数や fcfCall モードまたは fcfApply モードの関数を引数なしで呼び出した場合は通常の関数呼び出しとして実行される(ただし this が何になるかは違いが出る)。

DMonkey: Math.abs(無限大)が0になる不具合

コメントなし»
alert (Math.abs (Number.POSITIVE_INFINITY));  // 0
alert (Math.abs (Number.NEGATIVE_INFINITY));  // 0

この 0 は整数型の 0 です。浮動小数点型の 0.0 ではありません。

DMonkey: NaN は真の値として評価される

コメントなし»

NaN は真の値として評価されてしまいます。

alert (NaN ? 't' : 'f');  // t

DMonkey: Number#int で強制エラーになることがある

コメントなし»
try {
  alert (9223372036854775296.int);
//alert (-9223372036854775296.int); でも同じ
}
catch (e) {
  alert ('error=' + e);
}

9223372036854775296 以上の数、または -9223372036854775296 以下の数の .int プロパティを参照すると、try catch で捕捉できないエラーが発生します。

dmonkey_invalid_floating_point_operation

もっとも .int を参照することは普通はないので気にしなくても平気だと思います。普通じゃないスクリプトを書くとしても何か役に立つことがあるのかは不明です。

DMonkey: ===、!== 演算子の不具合

コメントなし»

number 型は内部で整数型と浮動小数点型に分かれているのですが、=== 演算子はそれぞれを別の型と見なしてしまい、数値として等価であっても false になります。

alert (1 === 1.0);  // false
alert (parseInt ('1') === parseFloat ('1'));  // false

!== 演算子は左辺と右辺の型が違うと false になる不具合が内部型にも該当し、数値として等価でなくてもfalse になります。

alert (1 !== 2.0);  // false
alert (parseInt ('1') !== parseFloat ('2'));  // false

DMonkey: !== 演算子の不具合

コメントなし»

厳密な比較を行う ===!== 演算子ですが、!== の方は左辺と右辺の型が違うと false になってしまいます。

alert (1 === 1); // true
alert (1 === 2); // false
alert (1 === '1');  // false

alert (1 !== 1); // false
alert (1 !== 2); // true
alert (1 !== '1');  // false

DMonkey: 名前付き関数式からの参照

コメントなし»

過去に書いた名前付き関数式で定義されたグローバル関数からはクロージャが使えないからの関連で。

参照先オブジェクトが属するスコープから抜ける前なら(クロージャとしての定義時の環境ではなく実行時の環境として)、名前付き関数式のブロック内から参照することは出来ます。

(function () {
  (function () {
    function common_load () {
      void function x () { alert (typeof common_load); };
    };
    common_load ();

    x ();  // function (まだ生きている)
  }) ();

  x ();  // undefined (スコープを抜けたので消失)
}) ();

Dorothy2 の Dorothy2A.dms では OnHttpRequest() 内で common_load() が定義されていて、実行終了まで OnHttpRequest() を抜けないので、common_load() で実行したスクリプトで名前付き関数式によって定義された関数内からも common_load() を呼び出せる、という挙動のようです。

あと名前付き関数式でなくて無名の関数式(を変数に代入したもの)でもスコープ抜けたら参照できなくなります。

DMonkey: 変数経由のnew演算子

コメントなし»
function Foo () {
  alert ('Foo constructor');
}
Foo.prototype.p = function () {
  alert ("this is Foo\nnameOf = " + nameOf (this));
};

function Baz () {
  alert ('Baz constructor');
}
Baz.prototype.p = function () {
  alert ("this is Baz\nnameOf = " + nameOf (this));
};

function test () {
  var f = new Foo ();  // Foo constructor
  f.p ();  // this is Foo, nameOf = Foo

  var Bar = Foo;
  var f2 = new Bar ();  // Foo constructor
  try { f2.p (); } catch (e) { alert (e); }  // ENameError

  var Baz = Foo;
  var f3 = new Baz ();  // Foo constructor
  f3.p ();  // this is Baz, nameOf = Baz
}
test ();

変数に関数を代入してその変数名で new すると、参照している関数がコンストラクタとして呼び出されますが、prototype として使われるのはその変数名と同名の関数の prototype になってしまいます。

名前付き関数式はグローバルスコープに対する関数宣言として動作する の末尾のエラー例も、これと同じことだと思います。

DMonkey: StringBuffer.indexOf() の不具合

コメントなし»
var sb = new StringBuffer ('aZ');
alert (sb.indexOf ('Z', 0));  // 1 
alert (sb.indexOf ('Z', 1));  // 1
alert (sb.indexOf ('Z', 2));  // 1 ※本来は -1
alert (sb.indexOf ('Z', 3));  // 1 〃
alert (sb.indexOf ('Z', 4));  // 1 〃

StringBuffer.indexOf()

  • 1バイトの文字列を検索。
  • 検索開始位置に length 以上の値を指定。
  • 末尾の文字が検索する文字と同じ。

という条件の時、-1 ではなく末尾の文字の位置を返してしまいます。

検索する文字列が2バイト以上なら問題ないようですが確証はありません。

DMonkey: void 演算子、++ 演算子、-- 演算子

コメントなし»

void 演算子は JavaScript では undefined を返しますが、DMonkey は null を返します。

alert (void 1);   // null

++ 演算子、-- 演算子は小数部を最近接偶数への丸め(round half to even)で整数化したあとに +1、-1 します。

var a = 1.2;
alert (++a);   // 2

var b = -2.5;
alert (--b);   // -3

おまけ。

alert (nameOf ({ }.prototype));   // Prototype