アンケートご協力のお願いgihyo.jpでは,2010年度に向けて豪華プレゼントが当たる読者属性アンケートを実施しております。ご協力ください。

gihyo.jp » DEVELOPER STAGE » 特集 » prototype.jsを読み解く » 第2回 Prototypeライブラリ(198~639行目)

prototype.jsを読み解く

第2回 Prototypeライブラリ(198~639行目)

ECMA-262 第三版について

第二回目です。

本連載中には,参考資料としてリンクできるところはリンクとして掲載するようにしています。しかし,もっとも重要であろうECMA-262 第三版については,PDFがあるだけなのでセクション番号とタイトルだけが記載されています。

仕様書としてはわかりにくい部類に入るかな,とも思いますが,JavaScriptの挙動を理解するには最終的にはこの文書を参照せざるを得ません。できればダウンロードしていつでも参照できるようにしておくといいでしょう。

また,この長大な仕様を翻訳してくださっている方も存在します。わかりにくい仕様なので,細かいニュアンスを押さえるには原文を参照するしかありませんが,概要を掴むには便利かと思います。

では,今回はStringオブジェクトから見ていきましょう。

String.interpret() と String.specialChar

0198: Object.extend(String, {
0199:   interpret: function(value) {
0200:     return value == null ? '' : String(value);
0201:   },
0202:   specialChar: {
0203:     '\b': '\\b',
0204:     '\t': '\\t',
0205:     '\n': '\\n',
0206:     '\f': '\\f',
0207:     '\r': '\\r',
0208:     '\\': '\\\\'
0209:   }
0210: });
0211: 

別の箇所で使うために,静的関数と定数値を定義します。

ここではprototypeプロパティではなくStringオブジェクト直下に直接追加しているので,呼び出すときはStringのインスタンス経由ではなく,String.interpret()やString.specialCharのように参照しないといけません。

199行目のString.interpret()では,引数として渡された値がnullなら空文字列を返し,それ以外ならそのままStringオブジェクトにして返す,ということをしています。

これにより,値がnullかどうかを気にせずに,文字列連結演算ができるようになります。

例:

result += String.interpret(replacement(match));

specialCharには特殊文字列と,それをエスケープした表現の対応が入っています。例えばString.specialChar['\n']とすると'\\n'(最初がバックスラッシュ,次がASCIIの'n'という2バイト)が返ります。

String.prototype.inspect()メソッドで,人間向けの文字列表現に変換する際に使われています。

String オブジェクトへの拡張

String.prototypeに対しては,数多くの拡張が入っています。これらは全てのStringオブジェクトで使えるメソッドとなります。

0212: Object.extend(String.prototype, {
0213:   gsub: function(pattern, replacement) {
0214:     var result = '', source = this, match;
0215:     replacement = arguments.callee.prepareReplacement(replacement);
0216: 
0217:     while (source.length > 0) {
0218:       if (match = source.match(pattern)) {
0219:         result += source.slice(0, match.index);
0220:         result += String.interpret(replacement(match));
0221:         source  = source.slice(match.index + match[0].length);
0222:       } else {
0223:         result += source, source = '';
0224:       }
0225:     }
0226:     return result;
0227:   },
0228: 

まずは213行目からの gsub()メソッドです。基本的にはpatternにマッチする文字列を見つけたら,slice()でマッチ位置より前の文字列をresultに足し(219行目),マッチ部分を置換した結果をresultに足し(220行目),ループ用のsource文字列をマッチ以後の文字列に更新する(221行目)ということを繰り返しています。

215行目でreplacementを関数オブジェクトにしている所が多少わかりにくいかもしれません。

ここで,argumentsはJavaScriptが自動的に用意してくれるオブジェクトで,関数に入るときに作成されます。そのarguments.calleeは今回呼び出された関数自身を示すFunctionオブジェクトが入ります(この場合gsub()関数)。String.prototype.gsub.prepareReplacement()という関数は,別途411行目で定義されていて,replacement引数として

  • 単純な置換後の文字列
  • RegExp.exec()の返す配列を引数として受け取り,受け取り置換後の文字列を返すFunctionオブジェクト
  • Prototypeライブラリが提供するTemplateクラスのオブジェクト

のどれが渡されたとしても,「RegExp.exec()の返す配列を引数として受け取り,置換後の文字列を返す」というFunctionオブジェクトに統一して返すようになっています。

……という挙動を意図しているのだと思われますが,実際の動作としては,replacemntとしてFunctionオブジェクトを渡していない場合には,必ずTemplateクラスのコンストラクタに渡されて,テンプレート文字列として処理されてしまいます。なので,Templateの特殊文字である#{...}という書式をreplacementに書いてしまうと,Template.evaluate()が処理してしまい意図と異なる結果となってしまうかもしれません。

例えば以下のようになります。

var s = "ABC";
var output = s.gsub('ABC', 'Template では #{...} と書きます。');
alert(output);    # 'Template では  と書きます。' が出力される
0229:   sub: function(pattern, replacement, count) {
0230:     replacement = this.gsub.prepareReplacement(replacement);
0231:     count = count === undefined ? 1 : count;
0232: 
0233:     return this.gsub(pattern, function(match) {
0234:       if (--count < 0) return match[0];
0235:       return replacement(match);
0236:     });
0237:   },
0238: 

String.prototype.gsub()がグローバル置換(マッチするもの全てに対して置換する)だったのに対して,sub()では最大指定された回数まで置換を行います。

233行目ではgsub()のreplacement引数にFuncitonオブジェクトを渡す方法を用いて,指定された回数を越えていたら置換を行わず,そうでなければ普通に置換する,という処理を行う関数を渡しています。

0239:   scan: function(pattern, iterator) {
0240:     this.gsub(pattern, iterator);
0241:     return this;
0242:   },
0243: 
0244:   truncate: function(length, truncation) {
0245:     length = length || 30;
0246:     truncation = truncation === undefined ? '...' : truncation;
0247:     return this.length > length ?
0248:       this.slice(0, length - truncation.length) + truncation : this;
0249:   },
0250: 

scan()はgsub()を呼び出しているだけですが,gsub()が置換後の文字列を返すのに対して,scan()は元の文字列をそのまま返します。パターンにマッチした文字列に対して指定の処理を行いたい,という場合に使えます。

truncate()では,lengthが指定されていなかった場合に30という値を設定し,truncationが指定されていない場合は文字列'...'を設定します。

Stringオブジェクトでは内部がUnicodeなので,文字列の長さを指定するときも日本語も1文字として数えます。

著者プロフィール

栗山淳(くりやまじゅん)

S2ファクトリー株式会社株式会社イメージソース所属。
本業はWeb制作会社の裏方。得意分野はFreeBSDやPerlのはずだが,必要に迫られるとHTML/CSSやJavaScriptも書く。

コメント

コメントの記入

パスサポ

多数の情報処理技術者試験対策書籍の発行実績を誇る技術評論社がお届けする,資格試験合格サイト「めざせ! 情報処理試験 パスサポ」が開設されました。

ピックアップ

サクセスストーリーに続く,快適サーバー運用管理のヒント!

データの増大,煩雑な管理,システムダウン,セキュリティなど,迫りくる課題からシステム管理者の負担を軽くするポイントを解説します。

gihyo.jp インフラエンジニア情報局

ネットワークやITにかかわるあらゆる業種で必要とされるインフラエンジニアに向けた技術情報や心構え,その魅力について多角的に紹介。

テストエンジニア ステーション

いま,ITに関わるあらゆる開発業務で注目されつつあるテスト系エンジニアをターゲットにしたコンテンツサイトを展開します。

一行クイックアンケート

gihyo.jpで取り上げてほしいネタは?

※検索はページ右上の検索ボックスをご利用ください。

その他の連載

キーパーソンが見るWeb業界

本連載はWeb Site Expert/gihyo.jpとの連動企画です。阿部淳也, 長谷川敦士, 森田雄のお三方による,Web業界をテーマにした座談会です。

きたみりゅうじの聞かせて珍プレー

ソフトウェア開発の現場で体験したトホホな失敗,思わずうなる珍プレーをきたみりゅうじ氏が四コママンガで紹介。みなさんからの投稿もお待ちしてます!

ActionScript 3.0で始めるオブジェクト指向スクリプティング

野中文雄氏が,簡単なスクリプトは書いたことがあるという初級者を対象に,ActionScript 3.0の基本からクラス定義までを解説します。

まだ間に合う「ITパスポート」受験対策 原山先生の短期合格塾

この連載では,4月18日のITパスポート試験の受験に向けて,短い期間で効率良く受験対策を行う方法や,確実に得点するための裏ワザなどを伝授していきます。

Ubuntu Weekly Recipe

Ubuntuの強力なデスクトップ機能を活用するための,いろいろなレシピをお届けします。

C/C++プログラマのためのDTrace入門

よくカーネルのチューニングや解析で活用されるDTraceですが,実はユーザプログラムの開発においても非常に有用です。連載ではC/C++プログラマやテストに関わる方向けにDTraceの使い方を解説します。

Blogopolisから学ぶ計算幾何

計算幾何学は,図形に関するアルゴリズムを研究するコンピュータサイエンスの一分野です。本連載では,ビジュアルブログ検索エンジン「Blogopolis」で採用されている計算幾何のアプローチを例に取り上げながら,計算幾何の初歩を実践的に学習します。

検索エンジンはいかにして動くのか?

本連載では, 今や誰もが利用している検索エンジンの中身を,全体の仕組みやデータ構造,アルゴリズムから分散インデックスまで,最近の研究事例も交えて紹介します。

連載一覧

gihyo.jp

  • DEVELOPER STAGE
  • ADMINISTRATOR STAGE
  • WEB+DESIGN STAGE
  • LIFESTYLE STAGE
  • SCIENCE STAGE
  • NEWS & REPORT

書籍案内

  • 新刊書籍
  • 書籍ジャンル一覧
  • 書籍シリーズ一覧
  • 新刊ピックアップ
  • ロングセラー
  • 電脳会議

定期刊行物一覧

  • Software Design
  • WEB+DB PRESS
  • Web Site Expert
  • 組込みプレス