JavaScriptでnew演算子をつけずにコンストラクタを実行する

またオブジェクト指向JavaScriptの原則で知った方法。実際に使うことはないと思うのだけど、こういう方法もあるのかと思ったので。

function Person(name){
    this.name = name;
    this.sayName = function(){
        console.log(this.name);
    };
}
// new演算子をつけてPerson関数を実行
var person1 = new Person('hanako');
person1.sayName(); //=> 'hanako'
console.log(person1); //=> Person {name: "hanako", sayName: function}

// new演算子をつけずにPerson関数を実行
var person2 = Person('tarou');
// person2.sayName(); // ここでエラー
console.log(window.name); //=> 'tarou'
console.log(person2); //=> undefined

こんな感じでnew演算子をつけないとオブジェクトが作成されませんし、グローバルオブジェクト(ブラウザの場合はwindow)を汚染してしまいます。

でも、ArrayやRegExpのオブジェクトはnewをつけなくてもオブジェクトが作成されるみたいです。

// new演算子をつけてArrayオブジェクトを作成
var arr1 = new Array(1,2,3,4,5);
console.log( arr1.join(',') ); //=> '1,2,3,4,5'
            
// new演算子をつけずにArrayオブジェクトを作成
var arr2 = Array(5,4,3,2,1);
console.log( arr2.join(',') ); //=> '5,4,3,2,1'

このようにnew演算子を使わずにオブジェクトを生成する方法としては、下記のようにinstanceof演算子を使えばできるとのこと。

function Person(name){
    if( this instanceof Person ){
        this.name = name;
        this.sayName = function(){
            console.log(this.name);
        };
    } else {
        console.log( this === window ); //=> true
        return new Person(name);
    }
}
// new演算子をつけてPerson関数を実行
var person1 = new Person('hanako');
person1.sayName(); //=> 'hanako'
console.log(person1); //=> Person {name: "hanako", sayName: function}

// new演算子をつけずにPerson関数を実行
var person2 = Person('tarou');
person2.sayName(); // 'tarou'
console.log(person2); //=> Person {name: "tarou", sayName: function}

つまり、thisがPersonか調べて、falseならばnew演算子をつけた自分自身を返すというような感じです。再帰みたいな感じですね。これは思いつきませんでした。

ちなみに、こういうコンストラクタを『スコープセーフなコンストラクタ』というようです。ただ、『スコープセーフ』で検索してもJavaScript関連のページがほとんどヒットしない(ヒットしても『オブジェクト指向JavaScriptの原則』の紹介ページ)ので、日本ではあまり一般的な呼び方ではなさそうです。

アメリカとかだと使われてる言葉なのだろうか? 英語で検索してみると下記のページがヒットしたけど。
New/Scope Safe Constructors in OO JavaScript :: Mike Pack Development

まあでも、こんなエントリー書いといてなんだけど、多分自分は使わないと思う。一見、オブジェクトを生成しているようには見えないわけだし。

コメント

  1. 通りすがり より:

    実際のビルドインコンストラクタはもっと確実な方法でコンストラクタ呼び出しかどうかを判断しています。
    それがユーザーランドでできるのはES6からです。

    • amyu より:

      コメントありがとうございます。
      なるほど~。そういうことなんですね。
      と言いたいところですが、残念ながら、今の自分には理解できそうにないです・・・。
      有用な情報なのにすみません。勉強します。

タイトルとURLをコピーしました