JavaScriptで小文字の「f」を使用した `new function()`


106

私の同僚は、JavaScriptで新しいオブジェクトを定義するために、小文字の「f」を使用して「new function()」を使用しています。すべての主要なブラウザでうまく機能しているようで、プライベート変数を隠すのにもかなり効果があるようです。次に例を示します。

    var someObj = new function () {
        var inner = 'some value';
        this.foo = 'blah';

        this.get_inner = function () {
            return inner;
        };

        this.set_inner = function (s) {
            inner = s;
        };
    };

「this」が使用されるとすぐに、someObjのパブリックプロパティになります。そのため、someObj.foo、someObj.get_inner()、someObj.set_inner()はすべて公開されています。さらに、set_inner()とget_inner()は特権メソッドであるため、クロージャーを介して「内部」にアクセスできます。

ただし、この手法への言及はどこにもありません。Douglas CrockfordのJSLintでさえ不満があります。

  • 奇妙な建設。「新規」を削除

この手法は本番環境で使用しており、うまく機能しているようですが、ドキュメント化されていないため、少し心配です。これが有効な手法であるかどうか誰かが知っていますか?


6
IIFE(「即時に呼び出される関数」)よりもあなたの構成を好みます。1:明示的な「インスタンス」オブジェクトは必要ありません。これは、JavaScriptの「これ」とまったく同じです。2:何も返す必要はありません。つまり、覚えておく必要はありません。受け入れられた回答の作成者でさえ、最初にインスタンスオブジェクトを返すのを忘れていました。人々は通常、新しい&これが嫌いな場合はIIFEを使用することを好みます。それには、正当な理由があります。DOMイベントを処理する関数thisがある場合、オブジェクトではなくイベントを発生させた要素を参照しますが、var instance = this代わりに使用できます。
Lee Kowalkowski

1
質問で「小文字のf」を指定することが重要なのはなぜですか。
ClearCloud8 2013

7
JavaScriptには「関数」関数(大文字のF付き)も存在するため、これは異なります。関数は新しい関数オブジェクトを作成できるコンストラクター関数ですが、関数はキーワードです。
Stijn de Witt 2013


@Bergi私はあなたのリンクを読みました。このパターンを信用しない理由はない。有効です。それは簡単です。何が問題なのか。JSLintはBTWのすべてについて文句を言っています:)
Stijn de Witt

回答:


64

私は以前にそのテクニックを見てきましたが、それは有効です。コンストラクター関数であるかのように関数式を使用しています

しかし、私見では、自動呼び出し関数式でも同じことができます。newそのように演算子を使用する意味はわかりません。

var someObj = (function () {
    var instance = {},
        inner = 'some value';

    instance.foo = 'blah';

    instance.get_inner = function () {
        return inner;
    };

    instance.set_inner = function (s) {
        inner = s;
    };

    return instance;
})();

new演算子の目的は、新しいオブジェクトインスタンスを作成し、[[Prototype]]内部プロパティを設定することです[Construct]。これが内部プロパティによってどのように行われるかを確認できます。

上記のコードは同等の結果を生成します。


1
セクション13のECMAScript 262仕様では、これをもう少し正式に説明しています。のようなものfunction foo () {}は、Functionオブジェクトを作成した結果を返します[おそらく新しいFunction()を使用]。それは構文糖です。
クリントンピアス

3
私はあなたがreturn instance;最後に欠けていると思います。そうでなければ、someObj単にになりますundefined。:-)
Matthew Crumley、2010

1
モジュール性と情報の隠蔽に関心があるなら、これをあきらめてrequire.jsのようなものを使い始めることをお勧めしますか?あなたはそこに途中です、なぜここに止まるのですか?非同期モジュール定義(require.jsが実装するもの)はこのユースケースをサポートし、スコープ、ネームスペース、および依存関係の管理に対処するためのツールセット全体を提供します。
Stijn de Witt 2013

文はすでに式であるため、関数の宣言を囲む括弧が原因の存在のために不必要であることに注意してください=
爆発の丸薬

途中の@StijndeWittは、require.jsを使用するために2倍の作業を行う必要があることを意味しますが、単純なケースではこれで十分な場合があります。
xr280xr 2015

15

あなたのコードはあまり変ではない構造に似ています

function Foo () {
    var inner = 'some value';
    this.foo = 'blah';

    ...
};
var someObj = new Foo;

9
それは単に似ているだけでなく、まったく同じことをします...唯一の例外は、彼らが別のオブジェクトを作成するためにFooを再利用できないことです。
kikito

3
OPのバージョンは、新しいsomeObj.constructorを介して再利用できます。ここでは、コンストラクターが名前空間に明示的に追加されています。適切なスタイルは、関数の使用目的によって異なります。また、このスタイルは(確かに標準ですが)Fooの前に新しい名前を忘れた場合に、グローバルネームスペースを設定できます。
Jブライアン価格

@kikitoこれは別のオブジェクトを作成するためにFooを再利用できないことをどういう意味ですか?var newObj = new Foo()は新しいインスタンスを作成する必要があります。
Bill Yang

1
@BillYangそれは5年前でした。わからない それ以来、JavaScriptには触れていません。
kikito

12

いくつかの側面を明確にし、Douglas CrockfordのJSLintがここでコードについて文句を言わないようにするために、インスタンス化の例をいくつか示します。

1. o = new Object(); // normal call of a constructor

2. o = new Object;   // accepted call of a constructor

3. var someObj = new (function () {  
    var inner = 'some value';
    this.foo = 'blah';

    this.get_inner = function () {
        return inner;
    };

    this.set_inner = function (s) {
        inner = s;
    };
})(); // normal call of a constructor

4. var someObj = new (function () {  
    var inner = 'some value';
    this.foo = 'blah';

    this.get_inner = function () {
        return inner;
    };

    this.set_inner = function (s) {
        inner = s;
    };
}); // accepted call of a constructor

例3では、値としての(...)内の式は関数/コンストラクターです。これは次のようになります:new(function(){...})()。したがって、例2のように終了角かっこを省略した場合でも、式は有効なコンストラクタ呼び出しであり、例4のようになります。

Douglas CrockfordのJSLintは、関数をインスタンスではなくsomeObjに割り当てたいと考えています。そして結局のところ、それは単なる警告であり、エラーではありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.