Pull to refresh

Comments 35

Каждый раз для простых выборок писать callback функцию только код марать. Безусловно если нужно элементы отфильтровать каким-нибудь хитрым макаром, то filter это наш выбор.
Сравните:

cars.filter(function(element, index, array) {
  return (element.brand == "audi" && (element.volume_engine == "2" || element.volume_engine == "3"));
});

и

cars.find({ brand:"audi", volume_engine:["2","3"] })

Ну можно чуть покороче, конечно :)

cars.filter(function(el) {
  return (el.brand == "audi" && (el.volume_engine == "2" || el.volume_engine == "3"));
});


Тут, конечно, CoffeeScript чуть более хорош:
(c for c in cars when c.brand == "audi" and c.volume_engine in ["2", "3"])
 cars.filter( (c) -> c.brand == "audi" and c.volume_engine in ["2", "3"] ) 

если не ошибся в синтаксисе
Да, разумеется. Просто мне синтаксис генераторов нравится :)
И ещё короче:
cars.filter(function(car) car.brand==="audi" && ["2", "3"].indexOf(car.volume_engine)>=0});


А в проекте и ещё чуть короче:
cars.filter(car => car.brand==="audi" && ["2", "3"].indexOf(car.volume_engine)>=0);


Или так:
[car for(car of cars) if(car.brand==="audi" && ["2", "3"].indexOf(car.volume_engine)>=0)]
Да уж, скорее бы Harmony «в люди» вышел: многие вещи значительно упрощают жизнь.
Ну возможно, тогда ваш find — это просто «сахар», тем более что он, как я понимаю, является расширением для прототипа Array.

А вообще, как идея — полноценно реализовать «язык запросов» MongoDB для обычных коллекций, да еще и с поддержкой аггрегирования было бы круто.
Ниже куча ссылок на подобные проекты.
Плюс еще есть TinyData, которая полноценный запросник по слабоструктурированным данным :)
Как вариант (я использую)
function Finder(arr){ this.data = arr; this.find = function(){ ...} }

И уже кручу верчу массивами, без прототипирования базовых объектов.

Как тот так
var cars = new Finder(arrayCars); cars.find({ })
Ну если посмотреть в код то он там и используется.

Не радует что идет расширение базового прототипа…
Всегда есть дилемма расширять ли базовый прототип. С одной стороны в академических кругах это возбраняется, с другой стороны без расширения базового прототипа не получится сделать каскадную выбору данных:

cars.find({...}).find({...}).find({...}).find({...});

Да и код такой:

cars.find({ brand: "audi" });

читать приятнее, чем вот такой:

find(cars,{ brand: "audi" });

То что вы свой метод дописываете это меньше из зол, это можно указать в readme и человек подключая вашу библиотеку будет знать что базовые классы расширяться методам и find и page. Но вот то что он не может знать, это то что добавляются еще и стандартные методы filter, indexOf, some. Вот такое неявство и есть зло. И вот представьте ситуацию, человек подключил вашу библиотеку, и чудным образом начал везде в коде юзать indexOf, some и прочее, потом отключил и у него херак, и в IE<9 все упало.
filter + функция, которая генерирует функцию.

arr.filter( Array.findFn({brand: 'audi'}) )

Можно из этого сделать обёртку find, но основной смысл — не парсить входные данные каждый раз, а иметь возможность во время инициализации один раз сделать

var audiFilter = Array.findFn({brand: 'audi'});
// а потом юзать во всех местах где надо выбрать audi 
arr.filter( audiFilter ); 


Кстати, это именно тот самый кейс где eval не является злом, а даёт ощутимое ускорение.

Array.findFn({brand: 'audi'}) // должно генерировать вот такую простую функцию
function(el){ return el['brand'] === 'audi'; }
— ну как вариант. Только в таком случае уже теряется элегантность кода, что ли.
Вот для кейса поиска равенства:
Array.find = function( match ){
    var i, pairs = [];
    for( i in match )
        match.hasOwnProperty( i ) &&
            pairs.push( 'el[\'' + i + '\'] === \''+ match[i] +'\''); // тут надо учесть экранирование кавычек в кей и в валью
            
    return Function('el', 'return ' + pairs.join(' && ')  + ';');
};
Array.prototype.find = function( match ){
    return this.filter( Array.find.call( this, match ) );
}


После этого можно делать вот так:
cars.find({brand: 'audi'});


А можно вот так:
var audiFilter = Array.find({ brand: 'audi' });
cars.filter( audiFilter );


Чейнинг тоже работает. ( cars.find({ brand: «audi» }).find({ awd: «да» }) ) Получается покрытие обоих кейсов.
Писать велосипеды это хорошо и полезно.
Но я все равно хочу обратить внимание, на замечательную библиотеку linq.js (как можно догадаться порт LINQ на JavaScript).
Позволяет делать с массивами данных все то же, что умеет оригинальный LINQ, т.е. выбрать данные любой вложенности по запросу любой сложности, отсортировать их по любому количеству полей и еще много всего.
Вы можете оценить возможности библиотеки посмотрев код из документации.
Интересная библиотека, но все же LINQ на мой взгляд гораздо функциональнее.
UFO just landed and posted this here
И sugarjs.com/ — кому-то такой вариант может показаться удобнее, особенно если был опыт работы с Prototype.
В стандарте ES6 есть метод Array.prototype.find и наиболее продвинутые его уже используют.
Плохо расширять прототип, у вас повторяется ситуация которая была с Prototype — стандартные методы реализованные по спецификации конфликтовали с методами библиотеки.

Тем более у вас же в библиотеки проверяется наличие этого метода и если я подключу es6-shim или когда браузеры реализуют Array#find ваша библиотека перестанет работать.

Правильно я понимаю, что .find (ES6) — это тот же .filter, только плюс механиз break при возврате null?
Что-то я не правильно прочитал описание метода, сейчас уже разобрался, что выше спросил глупость.
Ссылка правильная, это пример работы кроссфильтр на массиве в 200к записей. Кроссфильтр это не просто обертка на массиве, строится индекс по каждому из заданых полей и благодаря этому обеспечивается такой быстрый поиск.
Прошу прощения, интернет подвел. Теперь все открывается как нужно.
Справедливости ради стоит отметить, что LoDash умеет where-предикат на большинстве функций, принимающих коллбек.

Например, представим себе функцию filter (или функцию find, или функцию any).
Каждая из них в прямолинейном варианте принимает коллбек, который должен возвращать истиностное значение, результат проверки.
Но есть также два специальных синтаксиса:
1. Если передать вместо коллбека строку, то будет создан специальный коллбек, который возвращает атрибут передаваемого ему объекта с таким именем (т.н. pluck-стиль, по имени функции, выбирающей атрибуты объектов).
2. Если передать вместо коллбека словарь, то будет производиться сверка его свойств со сверками объекта (т.н. where-стиль). Именно этот случай описан у топикстартера.
Также такой специальный коллбек можно создавать самому.

Преимущество данной либы в возможности задавать оператор (использовать не только равенство). Схожие возможности удобны в ORM. Из знакомых мне, ORM Django позволяет такие фишки.
Автору несомненно благодарность за поделку. Всячески поддерживаю ваше начинание. Но есть несколько пожеланий:

1) Полностью согласен с комментарием пользователя termi в отношении фразы плохо расширять прототип. Видел ваш код накануне и это стало поводом воздержаться от звезды.

2) Жаль что написано не на coffee. Я сам хотел написать подобную поделку just for fun или присоединиться к разработке чего-то подобного. Но писать на чистом JS уже лень

В целом считаю идею проекта хоть и не новой, но весьма занятной и достойной потраченного времени. Желаю успехов!
Sign up to leave a comment.

Articles