eliace/ergo-js

View on GitHub
js/core/core-collections.js

Summary

Maintainability
A
1 hr
Test Coverage



//------------------------------------
//
// Методы для работы с коллекциями
//
//------------------------------------





(function(){

    var E = Ergo;




    /**
     * Последовательный обход каждого элемента массива или хэша
     *
     * в jquery есть функция $.each, но меня не устраивает порядок аргументов в замыкании
     *
     * @name Ergo.each
     * @function
     * @param {Object|Array} src объект, элементы которого необходимо просмотреть
     * @param {Function} callback функция, вызываемая для каждого элемента
     */
    E.each = function(src, callback){
        if( Array.isArray(src) ){
            // for(var i = 0; i < src.length; i++)
            //     callback.call(src, src[i], i)
            src.forEach(callback);
        }
        else {
            var obj = src;
            for(var i in obj){
                callback.call(obj, obj[i], i);
//                if( callback.call(obj, obj[i], i) === false ) return false;
            }
        }
    };

    /**
     * Фильтрация (как правило приводит к уменьшению размерности)
     *
     * Элемент попадает в итоговый объект
     *
     * @name Ergo.filter
     * @function
     * @param {Object|Array} src объект, элементы которого необходимо фильтровать
     * @param {Function} callback функция, вызываемая для каждого элемента
     * @returns {Object|Array} отфильтрованный объект или массив, в зависимости типа src
     */
    E.filter = function(obj, fn){
        var result;
        if( Array.isArray(obj) ) {
            result = obj.filter(fn);
        }
        else {
            result = {};
            for(var i in obj)
                if( fn.call(obj, obj[i], i) ) result[i] = obj[i];
        }
        return result;
    };



    /*
     * Фильтрация ключей.
     *
     * В результат попадают только индексы
     *
     * @param {Object|Array} src объект, элементы которого необходимо фильтровать
     * @param {Function} callback функция, вызываемая для каждого элемента
     * @returns {Object|Array} отфильтрованный объект или массив, в зависимости типа src
     */
    E.filterKeys = function(src, fn){
        var result = [];
        if(Array.isArray(src)) {
            for(var i = 0; i < src.length; i++)
                if(fn.call(src, src[i], i)) result.push(i);
        }
        else {
            for(var i in src)
                if(fn.call(src, src[i], i)) result.push(i);
        }
        return result;
    };




    /**
     * Отображение (размерность сохраняется)
     *
     * @name Ergo.map
     * @function
     * @param {Object|Array} src коллекция
     * @param {Function} callback функция, вызываемая для каждого элемента
     */
    E.map = function(obj, fn) {
        var a;
        if(Array.isArray(obj)) {
            a = obj.map(fn);
        }
        else {
            a = {};
            for(var i in obj) a[i] = fn.call(obj, obj[i], i);
        }
        return a;
    };


    /**
     * Свертка (размерность сохраняется)
     *
     * @name Ergo.reduce
     * @function
     * @param {Object|Array} src коллекция
     * @param {Function} callback функция, вызываемая для каждого элемента
     * @param {Any} initValue начальное значение (по умолчанию: [])
     */
    E.reduce = function(obj, fn, init_value) {
        var a = init_value || [];
        if(Array.isArray(obj)) {
            obj.reduce(fn, a);
        }
        else {
            for(var i in obj)
                fn.call(obj, a, obj[i], i, obj);
        }
        return a;
    }


    /**
     * Поиск первого элемента, удовлетворяющего критерию
     *
     * @name Ergo.find
     * @function
     * @param {Object|Array} obj коллекция
     * @param {Function|Any} criteria критерий
     */
    E.find = function(obj, criteria) {
        if(!$.isFunction(criteria)){
            var x = criteria;
            criteria = function(it) { return it == x; };
        }
        if(Array.isArray(obj)) {
            for(var i = 0; i < obj.length; i++)
                if(criteria.call(obj, obj[i], i)) return obj[i];
        }
        else {
            for(var i in obj)
                if(criteria.call(obj, obj[i], i)) return obj[i];
        }

        return null;
    };


    /**
     * Псевдоним для {@link Ergo.filter}
     *
     * @name Ergo.findAll
     * @function
     */
    E.findAll = E.filter;



    /**
     * Получение индекса (или ключа) элемента в коллекции
     *
     * Если критерий не является функцией, то используется метод Ergo.eq
     *
     * @name Ergo.keyOf
     * @function
     * @param {Object|Array} obj коллекция
     * @param {Function|Any} criteria критерий
     */
    E.keyOf = function(obj, criteria) {

        if(!$.isFunction(criteria))
            criteria = E.eq.bind(this, criteria);

        if( Array.isArray(obj) ) {
            for(var i = 0; i < obj.length; i++)
                if(criteria.call(obj, obj[i], i)) return i;
        }
        else {
            for(var i in obj)
                if(criteria.call(obj, obj[i], i)) return i;
        }
        return -1;
    };


    E.indexOf = E.keyOf;


    /**
     * Вызов метода для всех элементов коллекции
     *
     * Аргументы вызываемого метода передаются в виде массива
     *
     * Ergo.applyAll(items, 'show', [10, 45]);
     *
     * @name Ergo.applyAll
     * @function
     * @param {Object|Array} obj коллекция
     * @param {String} m_name имя метода
     * @param {Array} [args] список аргументов
     *
     */
    E.applyAll = function(obj, m_name, args) {
        if( Array.isArray(obj) ) {
            for(var i = 0; i < obj.length; i++) {
                if(obj[i][m_name]) obj[i][m_name].apply(obj[i], args || []);
            }
        }
        else {
            for(var i in obj) {
                if(obj[i][m_name]) obj[i][m_name].apply(obj[i], args || []);
            }
        }
    };

    /**
     * Вызов метода для всех элементов коллекции
     *
     * Аргументы вызываемого метода начинаются с 3 аргумента
     *
      * Ergo.callAll(items, 'show', 10, 45);
     *
     * @name Ergo.callAll
     * @function
     * @param {Object|Array} obj коллекция
     * @param {String} m_name имя метода
     *
     */
    E.callAll = function(obj, m_name) {
        var args = [];
        for(var i = 2; i < arguments.length; i++) args[i-2] = arguments[i];
        for(var i in obj) {
            if(obj[i][m_name]) obj[i][m_name].apply(obj[i], args);
        }
    };



    /**
     * Проверка, содержится ли элемент в коллекции
     *
     * @name Ergo.includes
     * @function
     * @param {Array|Object} obj коллекция
     * @param {Any} val значение
     */
    E.includes = function(obj, val) {
        if( Array.isArray(obj) )
            return obj.indexOf(obj) != -1;
        else {
            for(var i in obj)
                if(obj[i] === val) return true;
            return false;
        }
    };

    E.contains = E.includes;
//    E.is_include = E.includes;



    E.count = function(obj) {

        if(Array.isArray(obj)) {
            return obj.length;
        }

        return Object.keys(obj).length;
    };

    E.size = E.count;


    E.first = function(obj) {

        if(Array.isArray(obj)) {
            return obj[0];
        }

        return obj[Object.keys(obj)[0]];
    };





/**
     * Удаление элементов массива
     */
    E.remove = function(obj, criteria) {

        var f = criteria;

        if( !$.isFunction(criteria) ) {
            f = function(item, i) { return item === criteria; };
        }

        var indices = [];

        for(var i = 0; i < obj.length; i++) {
            if( f.call(obj, obj[i], i) ) {
                indices.push(i);
            }
        }

//        var arr = this;

        var removed = [];

        for(var i = indices.length-1; i >= 0; i--) {
            var idx = indices[i];
            removed.push(obj[idx]);
            obj.splice(idx, 1);
        }

        // indices.reverse().forEach( function(i) {
        //     removed.push(arr[i]);
        //     arr.splice(i, 1);
        // } );

        return removed;
    };



    E.uniq = function(obj) {
        var result = [];
        for(var i = 0; i < obj.length; i++) {
            if(result.indexOf(obj[i]) == -1) result.push(obj[i]);
        }
        return result;
    };






    /**
     * Удаление элемента из массива (массив уменьшает размерность)
     *
     * @name Ergo.remove
     * @function
     * @param {Object} arr массив
     * @param {Object} val удаляемый элемент
     */

    //TODO в качестве значения может выступать критерий, а удаление может происходить как из массива, так и из хэша

    // E.remove = function(arr, val) {
    //     var index = -1;
    //     for(var i = 0; i < arr.length; i++) {
    //         if(arr[i] === val) {
    //             index = i;
    //             break;
    //         }
    //     }
    //     if(index != -1) arr.splice(index, 1);

    //     return (index != -1);
    // };





})();