java.lang.StringとString.prototypeの関係

命名規則でクラスについては大文字それ以下は小文字というルールを決めているのでPHPとかでいうucfirst関数を書いているのですが型がJavajava.lang.StringだとcharAtを利用するとうまく行かないという話。jrunscriptで検証。

String.prototype.ucfirst = function(){
    return this.charAt(0).toUpperCase() + this.slice(1);
};

foo = 'foo';
foo.ucfirst(); // Foo ← 問題無

bar = new java.lang.String('bar');
bar.ucfirst();

script errot: (中略) : Type Error: Cannot find function toUpperCase.

toUpperCaseが見つからない...

結論から言うと、String.prototype拡張であっても型がjava.lang.Stringの場合にはcharAtを利用すると本当にcharを返すのでJavaScriptではNumberになる為に見つからくなる。加えて、どうやらECMAScript標準のScript.prototype.charAtではなくてjava.lang.String#charAtが優先的に利用されているようである。

String.prototype.test = function(){
    return charAt(0);
};
bar.test(); // 102

/*
 ECMAScript String#length は プロパティ
 JavaのString#length は メソッド
 */
String.prototype.testLength = function(){ return this.length(); };

new java.lang.String("foo").testLength(); // 3
"foo".testLength(); // error

まとめとして...

その後色々したあげくjava.lang.String型をJavaScriptから操作する場合には

  • String.prototype の拡張して利用可能である。
  • java.lang.Stringに同一のフィールド(メソッド/プロパティ)があればそちらが優先される。
  • java.lang.Stringに該当するフィールドが無い場合はECMAScriptネイティブのString.prototypeが利用される(といいつつcharCodeAtくらいしかない。)

ucfirst

String.prototype.ucfirst = function(){
   return this.slice(0,1).toUpperCase() + this.slice(1);
};

あ〜今日でテスト終了...。いろいろな意味で終わったな。北海道にあと1年か...な(--;