web-dev-qa-db-ja.com

NodeJSでオブジェクトを作成する推奨される方法は何ですか?

私はrequestモジュールのコンポジットを構築していますが、JS for Nodeでオブジェクトを構築する際のベストプラクティスは何かわかりません。

オプション1:

function RequestComposite(request) {
  return {
    get: function (url) { return request.get(url); }
  }
}
var comp = RequestComposite(request);
  • 注:非同期の方法でCBを呼び出す必要があることは知っていますが、説明を簡単にするためにそれを返します...

オプション2:

function RequestComposite(request) {
  this.request = request;
}

RequestComposite.prototype.get = function (url) { return this.request.get(url); };
var comp = new RequestComposite(request);

オプション3:

var RequestComposite = {
  init: function (request) { this.request = request; },
  get: function (url) { return request.get(url); }
}
var comp = Object.create(RequestComposite).init(request);

私は自分の道を見つけようとしましたが、オブジェクトの使用方法についてさらに混乱しました...

ブラウザーにオブジェクトを使用したい場合、答えは異なりますか?

ありがとう。

30
tounano

最も効率的な方法は次のとおりです。

  • コンストラクターでプロパティのみを設定します。

  • コンストラクターの.prototypeプロパティでメソッドを設定します。どうして?これは、オブジェクトを作成するたびに各メソッドを書き直すことを防ぐためです。このようにして、作成する各オブジェクトに対して同じプロトタイプをリサイクルします。メモリと時間の効率的。

  • プライベートプロパティにクロージャーを使用しないでください。なぜですか?:遅いため、このオブジェクトを継承チェーンで使用できません(疑似プライベート変数はオブジェクトに属しておらず、単にアクセス可能です)。代わりにアンダースコアを使用して、外部からアクセスすべきではないプライベートプロパティであることを示します。

  • Object.createの代わりにnewを使用します。より高速で、最後にObject.createは内部でnewを使用します。

つまり、次のようなものです。

var Person = function (name) {
    this._name = name;
};

Person.prototype.sayHello = function () {
    alert('My name is: ' + this._name);
};

var john = new Person('John');
john.sayHello();

編集

いくつかの追加情報:

  • Object.create vs newここにベンチマーク 。質問はnode.jsに対するものですが、同じ動作が予想されると思います。 (修正は大歓迎です)

  • プライベートプロパティをエミュレートするクロージャーこの質問 について読むことができます。プライベート/クロージャープロパティがオブジェクトに属さないという点は、プログラミングの事実です。これらは、オブジェクトメソッドによってアクセス可能ですが、オブジェクトには属しません。継承を使用する場合、それは大きな混乱です。また、コンストラクターで宣言されているメソッドのみがクロージャーにアクセスできます。プロトタイプで定義されたメソッドはそうではありません。

  • コンストラクタまたはプロトタイプのプロパティでメソッドを定義するこの質問 を読み、 このベンチマークを見てください

編集2016/04/15

3年前にここで行ったポイントは、パフォーマンスの観点からはまだ正しいですが、「推奨される方法」とは何かについての私の意見は、その間に少し変わっています。ファクトリ関数は一般に良いオプションであり、OPの最初のアプローチです。ほんの一例:

function Person(name) {
    return {
        sayHello: function () { alert('My name is: ' + name); }
    };
}

そして、ただやる:

var p = Person('John');

この場合、柔軟性(newカップリングなし、他の「ミックスイン」との構成の容易さ)および単純さ(this混乱なし、オブジェクトのインスタンス化の容易さ)をある程度の速度とメモリーと引き換えます。一般に、それらは完全に有効です。パフォーマンスの問題があり、その原因がオブジェクトの作成方法である場合は、別の方法に戻ります。 Object.createアプローチも優れており、何らかの理由でnewとファクトリー関数の中間に位置します(注:新しいclass構文は、new + prototypeの構文シュガーです)

要約:私の推奨する方法は、オブジェクト(ファクトリー関数)を作成する最も簡単で最も簡単な方法から始め、パフォーマンスの問題(ほとんどの場合は決してない)になったときに他の方法に移ります。

46
bgusach

JSで「クラス」と「オブジェクト」を作成する方法はたくさんあります。私はこの方法を好む:

var MyObject =
        function(args) {
            // Private
            var help = "/php/index.php?method=getHelp";
            var schedule = "/php/index.php?method=getSchedules";
            var ajax = function(url, callback, type) {
                //....
            }

            // Public
            this.property = 0;
            this.getInfo = function() {
                // ... 
            }

            // Constructor
            function(data) {
               this.property = data;
           }(args);
        };

var o = new MyObject();
7
ovnia

注:OOP構文に精通している場合は、 class を使用することもできます。これは、既存のプロトタイプベースの方法よりも単なる構文上の砂糖です。

オブジェクトを作成する4つの方法のパフォーマンス比較-コンストラクターを使用して(Chrome 61- https://jsperf.com/create-object-ways

オプションA:returnの使用(最速3x)

オプションB:{key:value}の使用(1.5x)

オプションC:prototype(1x)<-Baseの使用

オプションD:classの使用(1.02x)

オプションA最高のパフォーマンスを得るための縫い目。パフォーマンスの向上の一部は、newまたはobject.createの使用を避けるためです。公正な試用のために、コンストラクタとプロパティのないメソッドのみのオブジェクト間の別のテストを示します。


メソッドのみのオブジェクトを作成する4つの方法のパフォーマンス比較(Chrome 61- https://jsperf.com/create-static-object -ways

オプションA:returnの使用(3.2x)

オプションB:{key:value}の使用(最速3.3x)

オプションC:prototypeの使用(1.8x)

オプションD:classの使用(1.9x)

オプションBを上回りましたオプションAを少し上回りました。また、object.createによって引き起こされるボトルネックは、newを超えていました。


ベストプラクティス

オプションAreturnを使用)は、両方のシナリオで最高のパフォーマンスを発揮します。多くのメソッドとプロパティがある場合、この方法は少し面倒になります。

Option Aを使用して別のオブジェクトのコンストラクターとプロパティを分割し、Option B。このアプローチでは、パラメーターで追加のinstance参照を送信する必要がありますが、同じプロパティとコンストラクターを使用する複数のオブジェクトがある場合に役立ちます(一部のOOP継承も実現可能)。

例:

// Constructor & Properties Object (Using option A)
var UserData = function(request){

  // Constructor
  if ( request.name )
    var name = request.name;
  else
    var name = 'Not Available';

  if ( request.age )
    var age = request.age;
  else
    var age = null;


  // Return properties
  return {
    userName: name,
    userAge: age
  };

};


// Object methods (Using Option B)
var Adults = {

  printName: function(instance){ // Read propery example
    console.log( 'Mr. ' + instance.userName );
  },

  changeName: function(instance, newName){ // Write property example
    instance.userName = newName;
  },

  foo: function(){
    console.log( 'foo' );
  }

};


// Object methods (Using Option B)
var Children = {

  printName: function(instance){
    console.log( 'Master ' + instance.userName );
  },

  bar: function(){
    console.log( 'bar' );
  }

}


// Initialize
var userData = UserData ( {name: 'Doe', age: 40} );

// Call methods
Adults.printName(userData); // Output 'Mr. Doe'
Children.printName(userData); // Output 'Master Doe'

Adults.foo(); // Output 'foo'
Children.bar(); // Output 'bar'

Adults.changeName(userData, 'John');
Adults.printName(userData); // Output 'Mr. John'
1
SJ00