JavaScript の new 演算子の意味 ― 2005年10月24日 16時25分
JavaScript における new 演算子の動作は大まかにいって以下のとおりである。(new F()
とした場合。)
- 新しいオブジェクトを作る。
- 1 で作ったオブジェクトの [[Prototype]] 内部プロパティ (
__proto__
プロパティ) にF.prototype
の値を設定する。F.prototype
の値がオブジェクトでないのなら代わりにObject.prototype
の値を設定する。
- F を呼び出す。このとき
this
の値は 1 で作ったオブジェクトとし、引数には new 演算子とともに使われた引数をそのまま用いる。 - 3 の返り値がオブジェクトならそれを返す。そうでなければ 1 で作ったオブジェクトを返す。
ここで「オブジェクトである」というのはプリミティブ値 (文字列、数値、真偽値、undefined
、null
) ではないということだ。new String("string")
、new Number(123)
、new Boolean(true)
はオブジェクトだが "string"
、123
、true
はオブジェクトではない。
コードであらわすと以下のようになる。
Function.prototype.construct = function () {
var newInstance = new Object();
if (this.prototype instanceof Object)
newInstance.__proto__ = this.prototype;
var returnValue = this.apply(newInstance, arguments);
if (returnValue instanceof Object)
return returnValue;
return newInstance;
};
var o = F.construct(arg); // == new F(arg)
new F()
としたとき、実際に F が呼び出される前に新たなオブジェクトが作られるが、そのオブジェクトの生成にあたっては F.prototype
の値が参考にされるのみで F 自体は直接関わってはいない。だからこそ一時的なコンストラクタを使って継承を実現ということもできる。
そして、それと同様に考えれば、「prototype.js を用いた OOP で、後方参照できるクラスを宣言する」(Noncommutative Field) で触れられていた配列として渡された引数を用いて new するということは以下のように実現できる。
Function.prototype.applyNew = function (args) {
var Constructor = function () {};
Constructor.prototype = this.prototype;
var instance = new Constructor();
var result = this.apply(instance, args);
return (result instanceof Object) ? result : instance;
};
var o = F.applyNew([param1, param2]); // == new F(param1, param2)
余談になるが、F の返り値がオブジェクトでないとき、new F()
の値には F の返り値ではなく新たに作られたオブジェクトが使用されるというのは改めて仕様書を読むまで気づかなかった。これまで以下のように書いていたのはまったくの見当違いだったのか。(というかろくにテストしていないのがばればれ。)
function F(arg)
{
if (!arg) return null;
...
}
var o = new F(someArg);
参考
コメント
_ Word ― 2005年10月25日 09時18分
_ ほげほげ ― 2011年07月07日 13時59分
※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。
※投稿には管理者が設定した質問に答える必要があります。
トラックバック
このエントリのトラックバックURL: http://nanto.asablo.jp/blog/2005/10/24/118564/tb