Кастомные JavaScript коллекции в стиле Laravel 5
Создаем и расширяем кастомные коллекции моделей/записей на JavaScript в стиле Laravel 5.
Чтобы не выдумывать ничего нового, за основу берем библиотеку collect.js:
npm install -S collect.js
Библиотека предоставляет метод macro() для глобального добавления новых методов в прототип объекта класса (по факту, функции) Collection:
collect().macro('newCollectionMethod', functionName);
Проблемы и ограничения:
- Метод macro() не позволяет расширять наши кастомные классы EntityCollection (или я что-то упустил).
- Мы не можем наследовать (extends) класс Collection в EntityCollection поскольку большинство методов коллекции возвращают новый объект типа Collection, а не наш EntityCollection.
Я остановился на следующем решении - в конструкторе нашей EntityCollection расширяем прототип класса свойствами/методами объекта типа Collection.
Пример класса коллекции:
import UserModel from './UserModel';
import collect from 'collect.js';
/**
* @class UserCollection
* @property {Array} items
*/
class UserCollection {
constructor(items) {
items = items || [];
let collectionProperties = Object.getPrototypeOf(collect());
Object.assign(this, collectionProperties);
this.items = items.map(function(item, i) {
return new UserModel(item);
});
}
customCollectionMethod() {
console.log('customCollectionMethod');
// @note See returns logic in origin methods! >>
// return new this.constructor(collection);
}
}
export default MissionCollection;
Свойства прототипа Collection можно получить разными способами:
let collectionProperties = collect().__proto__;
let collectionProperties = (new Collection).__proto__;
let collectionProperties = Object.getPrototypeOf(collect());
Расширить прототип нашей коллекции, возможно, правильнее было бы так (документация):
Object.defineProperties(UserCollection, props);
Но, нужно формировать специфический объект расширяемых свойств.
Или так (не поддерживает Safari) (документация):
Object.setPrototypeOf(UserCollection, collect().__proto__);
А есть еще Object.create:
Object.create(proto[, propertiesObject]);
Но есть ли необходимость усложнять? Не готов ничего утверждать, увы, нет времени для выяснения.
Замечания, предложения, конструктивная критика - приветствуются.
Успехов в разработке!
#collect.js, #javascript collection, #javascript collection like laravel 5