プリミティブ文字列値とStringオブジェクトには違いがあります。
'foo' // primitive
new String('foo') // object
文字列プリミティブで String メンバー関数を呼び出すと、関数内の値になる String オブジェクトにラップされthisます。(この動作については、以下で詳しく説明します。)
したがって、 inremoveExtensionはオブジェクトですthis。String一方、組み込み関数this.substrはプリミティブを返します。それが定義されているだけです。thisしたがって、 ( String objectthis.substr ) を返すときと(string Primitive )の結果を返すときは、異なることがわかります。オブジェクトの文字列プリミティブ バージョンを返したい場合はthis、単にthis.toString.
Numbersなどのどのプリミティブでも同じラッピング動作が見られます。
Number.prototype.returnThis = function() { return this; }
typeof 2; // 'number'
typeof (2).returnThis() // 'object' (a Number object, specifically)
なぜこれが起こるのか本当に知りたい場合は、ECMAScript 仕様にあります。
10.4.3 機能コードの入力
関数オブジェクト F に含まれる関数コードの実行コンテキストに制御が入ると、次の手順が実行されます。
- 機能コードが厳格なコードの場合は、 を に設定
ThisBindingしthisArgます。
- それ以外の場合、thisArg が null または未定義の場合は
ThisBinding、グローバル オブジェクトに設定します。
Type(thisArg)が Object でない場合は、 を に設定ThisBindingしToObject(thisArg)ます。
- ....
ポイント #3 が重要です。プリミティブ値 (つまり、非オブジェクト) で関数を呼び出すと、対応するオブジェクト形式に変換されます。