Linq-Подобный Синтаксис Для Нокаута

Прошел год с тех пор, как наша команда занималась разработкой веб-портала с использованием паттерна MVVM и фреймворка Knockout в частности.

Понемногу накапливался опыт, появлялись различные решения, хорошие и плохие практики, и теперь, так сказать, созрело.

Библиотека для синтаксиса linq в javascript уже есть, linq.js, и мы долго думали, стоит ли привносить ее в наш проект. И даже примеры использования вместе с нокаутом в интернете Есть .

Идея, которая пришла мне в голову, заключалась в том, чтобы инкапсулировать создание вычисляемых внутри методов Linq. Для сравнения код из скрипки:

  
  
  
  
  
  
   

this.filteredItems = ko.computed(function() { var term = this.searchTerm(); return this.items.where(function(item) { return item.name.indexOf(term) > -1; }); }, this);

и код, который я хотел бы написать вместо этого:

this.filteredItems = this.items .

Where(function(item) { return item.name.indexOf(this.searchTerm()) > -1; });

После описанной выше инкапсуляции вычислений выяснилось, что библиотека linq.js на самом деле не нужна.

В нокаут встроено достаточно инструментов.

Более того, вам нужно написать их всего один раз, и никакой разницы снаружи не будет, даже если это самый прямой и простой цикл for. Итак, сначала подготавливаем объект с методами:

var methods = { First: function(predicate) { return ko.computed(function() { return ko.utils.arrayFirst(this(), predicate); }, this, { deferEvaluation: true }); }, Select: function(func) { return ko.computed(function() { return ko.utils.arrayMap(this(), function(item) { return ko.utils.unwrapObservable(func(item)); }); }, this, { deferEvaluation: true }); }, SelectMany: function(func) { return ko.computed(function() { var result = []; ko.utils.arrayForEach(this(), function(item) { result = result.concat(ko.utils.unwrapObservable(func(item))); }); return result; }, this, { deferEvaluation: true }); }, Where: function(predicate) { return ko.computed(function() { return ko.utils.arrayFilter(this(), predicate); }, this, { deferEvaluation: true }); }, Distinct: function(func) { if (!func) { return this.DistinctValue(); } return ko.computed(function() { var obj = {}; return ko.utils.arrayFilter(this(), function(item) { var val = ko.utils.unwrapObservable(func(item)); return obj[val] ? false : (obj[val] = true); }); }, this, { deferEvaluation: true }); }, DistinctValue: function() { return ko.computed(function() { var obj = {}; return ko.utils.arrayFilter(this(), function(val) { return obj[val] ? false : (obj[val] = true); }); }, this, { deferEvaluation: true }); }, Sum: function(func) { return func ? this.Select(func).

Sum() : this.SumValue(); }, SumValue: function() { return ko.computed(function() { var result = 0; ko.utils.arrayForEach(this(), function(item) { result = result + (+item); }); return result; }, this, { deferEvaluation: true }); }, StringJoin: function(joinString) { joinString = joinString || ', '; return ko.computed(function() { return this().

join(joinString); }, this, { deferEvaluation: true }); }, };

Второй шаг — назначить методы obsrvableArray и вычислить:

for (var i in methods) { ko.observableArray.fn[i] = methods[i]; ko.computed.fn[i] = methods[i]; }

Блюдо готово, давайте его использовать.

Примеры:

self.DistinctEntities = policy.Coverages .

SelectMany(function(item) { return item.Entities; }) .

Distinct(function(item) { return item.Name; }); self.EmployeeCount = policy.CoveredTotalCurrentYear .

Sum(function (item) { return item.Quantity; }); self.LineOfCoverageColumnName = policy.Coverages .

Select(function (item) { return item.LineOfCoverage.ShortDisplayName; }) .

StringJoin();

И для начала метод Map, аналогичный методу Select, но для сложных/затратных операций, в частности, когда для каждой модели данных во входном массиве нужно создать модель представления в выходном массиве.

При добавлении элемента во входной массив операция Select повторно вызовет лямбду для всех элементов массива, а операция Map сделает это только для вновь добавленного элемента:

Map: function (converter) { var oldValues = []; var oldResults = []; return ko.computed(function() { var values = this().

slice(); var results = []; ko.utils.arrayForEach(values, function(item) { var index = oldValues.indexOf(item); results.push(index > -1 ? oldResults[index] : converter(item)); }); oldValues = values; oldResults = results; return results; }, this, { deferEvaluation: true }); },

Использование:

self.Coverages = policy.Coverages.Map(function(coverage) { return new coverageViewModel(coverage); });

PS Список методов пока не охватывает весь набор LinQ, но расширить его несложно.

Теги: #js #LINQ #knockout #JavaScript #.

NET

Вместе с данным постом часто просматривают: