3595: enum regexp_tinyid { 3596: REGEXP_SOURCE = -1, 3597: REGEXP_GLOBAL = -2, 3598: REGEXP_IGNORE_CASE = -3, 3599: REGEXP_LAST_INDEX = -4, 3600: REGEXP_MULTILINE = -5, 3601: REGEXP_STICKY = -6 3602: }; 3607: static JSPropertySpec regexp_props[] = { 3608: {"source", REGEXP_SOURCE, RO_REGEXP_PROP_ATTRS,0,0}, 3609: {"global", REGEXP_GLOBAL, RO_REGEXP_PROP_ATTRS,0,0}, 3610: {"ignoreCase", REGEXP_IGNORE_CASE, RO_REGEXP_PROP_ATTRS,0,0}, 3611: {"lastIndex", REGEXP_LAST_INDEX, REGEXP_PROP_ATTRS,0,0}, 3612: {"multiline", REGEXP_MULTILINE, RO_REGEXP_PROP_ATTRS,0,0}, 3613: {"sticky", REGEXP_STICKY, RO_REGEXP_PROP_ATTRS,0,0}, 3614: {0,0,0,0,0} 3615: }; 3616: 3617: static JSBool 3618: regexp_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) 3619: { 3620: jsint slot; 3621: JSRegExp *re; 3622: /* 前処理 */ 3630: slot = JSVAL_TO_INT(id); 3631: if (slot == REGEXP_LAST_INDEX) 3632: return JS_GetReservedSlot(cx, obj, 0, vp); 3633: 3634: JS_LOCK_OBJ(cx, obj); 3635: re = (JSRegExp *) JS_GetPrivate(cx, obj); 3636: if (re) { 3637: switch (slot) { 3638: case REGEXP_SOURCE: 3639: *vp = STRING_TO_JSVAL(re->source); 3640: break; 3641: case REGEXP_GLOBAL: 3642: *vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_GLOB) != 0); 3643: break; 3644: case REGEXP_IGNORE_CASE: 3645: *vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_FOLD) != 0); 3646: break; 3647: case REGEXP_MULTILINE: 3648: *vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_MULTILINE) != 0); 3649: break; 3650: case REGEXP_STICKY: 3651: *vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_STICKY) != 0); 3652: break; 3653: } 3654: } 3655: JS_UNLOCK_OBJ(cx, obj); 3656: return JS_TRUE; 3657: }regexp_getProperty 関数内では、3630 行目で変数 slot に id の値である -1 が収められます。3638 行目でそれが定数 REGEXP_SOURCE と一致することで、-1 というプロパティ名に対し source プロパティと同じ値が返ってくるのです。
source に対する -1 のような、プロパティを表す整数を tiny id[LINK] と呼びます。SpiderMonkey では、プロパティごとにゲッタ / セッタ用フック関数を設定するのではなく、特定のオブジェクトの全プロパティに共通するゲッタ / セッタ用フック関数を使うと、JavaScript コードからの tiny id によるアクセスがプロパティ名によるアクセスと同一視されてしまうそうです。
より短い SpiderMonkey の判別法
外部から tiny id を使ってプロパティにアクセスできるのは正規表現オブジェクトに限りません。文字列の場合は length プロパティに対する tiny id として -1 が割り当てられ、それにより外部から参照できます。これを使えば、結果が真偽値となるような SpiderMonkey の判別は次の 12 文字で可能です。
SM=""[-1]==0
「ブラウザ判別」としての不備
最初に紹介したページに掲載されている判別法は、いずれもブラウザの JavaScript エンジンの差異を用いたものです。これらは JavaScript エンジンの内部実装に大きく依存するものであり、エンジンのちょっとした変更で期待した動作をしなくなる可能性も否定できません。実際、そこで Firefox 3 の判別用と紹介されている以下のコードの結果は、Firefox 3.1 では false となります。SpiderMonkey は現在、関数オブジェクトでは
古びて非効率的な方法を捨て、プロパティごとにゲッタ用フック関数を指定するようにしたからです。//Firefox 3 by me:- FF3=(function x(){})[-5]=='x'
セコメントをする