Какой рекомендуемый способ создания объектов в 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);
Я пытался найти свой путь, но я еще больше смутился о том, как использовать объекты...
Будет ли ответ другим, если я хочу использовать объекты для браузеров?
Спасибо.
Ответы
Ответ 1
Наиболее эффективный способ заключается в следующем:
Поместите всю необходимую инициализацию в конструктор (например, проверьте параметры конструктора, установите свойства и т.д.).
Установите методы в свойстве .prototype
конструктора. Почему? Потому что это не позволяет переписывать каждый метод каждый раз, когда вы создаете объект. Таким образом вы перерабатываете один и тот же прототип для каждого создаваемого вами объекта. Эффективен в памяти и экономит время кодирования.
Не используйте закрытие для частной собственности. Почему? Он медленный и не позволяет использовать этот объект в цепочке наследования (псевдоприватные переменные не принадлежат объекту, они просто доступны). Вместо этого обычной практикой является использование подчеркивания при объявлении свойства объекта, чтобы указать, что это свойство _private, к которому нельзя обращаться извне.
Используйте new
вместо Object.create
. Проще запомнить, если вы привыкли к другим языкам ООП; и в конце new
использует Object.create
под капотом.
Другими словами, что-то вроде этого:
var Person = function (name) {
this._name = name;
};
Person.prototype.sayHello = function () {
alert('My name is: ' + this._name);
};
var john = new Person('John');
john.sayHello();
EDIT
Некоторая дополнительная информация:
Object.create vs new. Тест здесь. Хотя вопрос к Node.js, я думаю, что такое же поведение следует ожидать. (любые исправления приветствуются)
Замыкания для эмуляции частных свойств. Вы можете прочитать о в этом вопросе.. То, что свойства private/closure не принадлежат объекту, является фактом программирования: они доступны для методов объекта, но не принадлежат объекту. При использовании наследования это большой беспорядок. Кроме того, только методы, которые объявлены в конструкторе, имеют доступ к замыканию. Методы, определенные в прототипе, отсутствуют.
Определение методов в конструкторе или свойстве прототипа: прочитайте этот вопрос и посмотрите этот тест
ОБНОВЛЕНИЕ 15/04/2016
Точки, которые я высказал здесь три года назад, все еще верны с точки зрения производительности, но мое мнение о том, что такое "рекомендуемый путь", за это время немного изменилось. Фабричные функции в целом являются хорошим вариантом, который будет первым подходом OP. Просто пример:
function Person(name) {
return {
sayHello: function () { alert('My name is: ' + name); }
};
}
а затем просто сделайте:
var p = Person('John');
В этом случае вы торгуете гибкостью (без связи new
, простотой компоновки с другими "дополнениями") и простотой (без путаницы this
, легким созданием объектов) для некоторой скорости и памяти. В целом они совершенно действительны. Если у вас есть проблемы с производительностью, и это из-за этого способа создания объектов, вернитесь к другому методу. Подход Object.create
также хорош, он как-то падает в середине new
и заводских функций (примечание: новый синтаксис class
является синтаксическим сахаром для new
+ prototype
)
Подводя итог: мой рекомендуемый способ - начать с самого простого и простого способа создания объектов (фабричные функции), а затем перейти к другим методам, когда вы сталкиваетесь с проблемами производительности (чего в большинстве случаев никогда не бывает).
Ответ 2
Существует множество способов создания "классов" и "объекта" в 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();
Ответ 3
Примечание. Если вы более знакомы с синтаксисом ООП, вы также можете использовать class
, который является просто синтаксическим сахара над существующим прототипом.
Сравнение производительности между четырьмя способами создания объекта - с конструктором (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
. Чтобы просто провести справедливое судебное разбирательство, вот еще один тест между объектами только для метода без конструктора и свойств.
Сравнение производительности между четырьмя способами создания объектов только для методов (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
) лучше всего работает в обоих сценариях. Этот способ может стать немного беспорядочным, если у вас много методов и свойств.
Я предпочитаю разделить конструктор и свойства в отдельном объекте, используя Вариант A и методы в другом объекте, используя Вариант B. Этот подход требует отправки дополнительной ссылки instance
в параметрах, но может быть полезен, если у вас есть несколько объектов, использующих одни и те же свойства и конструктор. (Некоторое наследование ООП также может быть достигнуто).
Пример:
// 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'