it-swarm.com.ru

Каков рекомендуемый способ создания объектов в NodeJS?

Я создаю композит для модуля request, однако я не уверен, как лучше всего строить объекты в JS для 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);

Я пытался найти способ обойти, но я еще больше запутался в том, как я должен использовать объекты ...

Будет ли другой ответ, если я хочу использовать объекты для браузеров?

Благодарю.

29
tounano

Наиболее эффективным способом является следующее:

  • Установить только свойства в конструкторе.

  • Установите методы в свойстве .prototype конструктора. Зачем? потому что это предотвращает переписывание каждого метода каждый раз, когда вы создаете объект. Таким образом вы перерабатываете один и тот же прототип для каждого создаваемого вами объекта. Эффективно в памяти и во времени.

  • Не используйте закрытие для частной собственности. Почему ?: Это медленно и мешает вам использовать этот объект в цепочке наследования (псевдоприватные переменные не принадлежат объекту, они просто доступны). Вместо этого используйте подчеркивание, чтобы указать, что это частное свойство, к которому нельзя обращаться извне.

  • Используйте new вместо Object.create. Это быстрее, и в конце 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, я думаю, что такое же поведение следует ожидать. (любые исправления приветствуются)

  • Замыкания для эмуляции частных свойств: вы можете прочитать о в этом вопросе. . То, что свойства private/closure не принадлежат объекту, является фактом программирования: они доступны для методов объекта, но не принадлежат объекту. При использовании наследования это большой беспорядок. Кроме того, только методы, которые объявлены в конструкторе, имеют доступ к замыканию. Способов, определенных в прототипе, нет.

  • Определение методов в конструкторе или свойстве прототипа: прочитайте этот вопрос и посмотрите этот тест

РЕДАКТИРОВАТЬ 15/04/2016

Точки, которые я высказал здесь три года назад, все еще верны с точки зрения производительности, но мое мнение о том, что такое «рекомендуемый путь», немного изменилось за это время. Фабричные функции в целом являются хорошим вариантом, который будет первым подходом ОП. Просто пример:

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

а затем просто сделайте:

var p = Person('John');

В этом случае вы торгуете гибкостью (отсутствие связи new, простота компоновки с другими «дополнениями») и простотой (отсутствие беспорядка this, легкая реализация объекта) для некоторой скорости и памяти. В целом они совершенно действительны. Если у вас есть проблемы с производительностью, и это из-за этого способа создания объектов, вернитесь к другому методу. Подход Object.create также хорош, он каким-то образом попадает в середину функций new и фабрики (примечание: новый синтаксис class является синтаксическим сахаром для new + prototype)

Подводя итог: мой рекомендуемый способ - начать с самого простого и легкого способа создания объектов (фабричные функции), а затем перейти к другим методам, когда вы сталкиваетесь с проблемами производительности (чего в большинстве случаев никогда не бывает).

45
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.


Лучшая практика

Вариант A (с использованием return) лучше всего работает в обоих сценариях. Этот способ может стать немного грязным, если у вас много методов и свойств.

Я предпочитаю разделять конструктор и свойства в отдельном объекте, используя 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