Skip to main content
2 of 11
added 32 characters in body
konijn
  • 33.8k
  • 5
  • 69
  • 264

A package for basic utility functions

Compare to underscorejs if it pleases you. Once again, I hope this is well commented. Please let me know what comments/improvements I can add.

Please review all aspects of this code.

/***************************************************************************************************

    **UTILITY
     - additional coverage for looping, type checking, extending ...
     - consistent ordering, naming conventions ...
     - fewer function branches
     - increased type checking and modularity
     - vector based unit testing
    /**************************************************************************************************/
    
    // self used to hold client or server side global ( window or exports )
    (function (self, undef) {
    
        "use strict";
    
        // holds (P)ublic properties
        var $P = {},
    
        // holds p(R)ivate properties
            $R = {},
    
            // native methods (alphabetical order)
            nativeFilter = Array.prototype.filter,
            nativeIsArray = Array.isArray,
            nativeSlice = Array.prototype.slice,
            nativeSome = Array.prototype.some,
            nativeToString = Object.prototype.toString;
    
    /******************************************************************************/
    // GLOBAL MANAGEMENT
    
        $P.noConflict = (function () {
    
            // $R.g holds the single global variable, used to hold all packages
            // methods
            $R.g = '$A';
            $R.previous = self[$R.g];
    
            // utility is required by all other packages
            // start the "pack"age list
            $P.pack = {
                utility: true
            };
    
            return function () {
                var temp = self[$R.g];
                self[$R.g] = $R.previous;
                return temp;
            };
        }());
    
    /******************************************************************************/
    // TYPE CHECKS
    
        $P.isType = function (type, obj) {
            return $P.getType(obj) === type;
        };
    
        // returns type in a captialized string form
        // typeof is only accurate for function, string, number, boolean, and
        // undefined.  null and array are both incorrectly reported as object
        $P.getType = function (obj) {
            return nativeToString.call(obj).slice(8, -1);
        };
    
        $P.isFalse = function (obj) {
            return obj === false;
        };
    
        $P.isUndefined = function (obj) {
            return obj === undef;
        };
    
        $P.isNull = function (obj) {
            return obj === null;
        };
    
        $P.isNumber = function (value) {
            return (typeof value === 'number') && isFinite(value);
        };
    
        // detects null or undefined
        $P.isGone = function (obj) {
            return obj == null;
        };
    
        // detects anything but null or undefined
        $P.isHere = function (obj) {
            return obj != null;
        };
    
        // detects null, undefined, NaN, ('' ""), 0, -0, false
        $P.isFalsy = function (obj) {
            return !obj;
        };
    
        // detects any thing but null, undefined, NaN, ('' ""), 0, -0, false
        $P.isTruthy = function (obj) {
            return !!obj;
        };
    
        // shortcut as their are only two primitive boolean values
        // detects a "boxed" boolean as well
        $P.isBoolean = function (obj) {
            return obj === true || obj === false ||
                nativeToString.call(obj) === '[object Boolean]';
        };
    
        // delegates to native
        $P.isArray = nativeIsArray || function (obj) {
            return nativeToString.call(obj) === '[object Array]';
        };
    
        // jslint prefers {}.constructor(obj) over Object(obj)
        $P.isObjectAbstract = function (obj) {
            // return obj === Object(obj);
            return !!(obj && (obj === {}.constructor(obj)));
        };
    
        // has a numeric length property
        $P.isArrayAbstract = function (obj) {
            return !!(obj && obj.length === +obj.length);
        };
    
    /******************************************************************************/
    // LOOPING
    
        $P.someIndex = function (arr, func, con) {
            var ind,
                len;
    
            // prevent type errors, note function is validated
            if ((arr == null) || (arr.length !== +arr.length) || (typeof func !== 'function')) {
                return;
            }
    
            // delegate to native some()
            if (nativeSome && arr.some === nativeSome) {
                return arr.some(func, con);
            }
    
            // if the function passes back a truthy value, the loop will terminate
            for (ind = 0, len = arr.length; ind < len; ind++) {
                if (func.call(con, arr[ind], ind, arr)) {
                    return true;
                }
            }
            return false;
        };
    
        $P.someKey = function (obj, func, con) {
            var key;
    
            // prevent type errors
            // for-in will filter out null and undefined
            if ((obj == null) || (typeof func !== 'function')) {
                return;
            }
            for (key in obj) {
                if (obj.hasOwnProperty(key)) {
    
                    // if the function passes back a truthy value,
                    // the loop will terminate
                    if (func.call(con, obj[key], key, obj)) {
                        return true;
                    }
                }
            }
            return false;
        };
    
        // loop through space separated "tokens" in a string
        $P.eachString = function (str, func, con) {
    
            // prevent type errors
            if (typeof str !== 'string' || str === "" ||
                    typeof func !== 'function') {
                return;
            }
            $P.someIndex(str.split(/\s+/), func, con);
        };
    
        // does not extend through the prototype chain
        // implemented for objects only
        $P.extend = function (obj) {
    
            // loop througth elements beyond obj
            $P.someIndex(nativeSlice.call(arguments, 1), function (val) {
    
                // extend it
                $P.someKey(val, function (val_inner, key) {
                    obj[key] = val_inner;
                });
            });
            return obj;
        };
    
        // extends non-prototype properties from obj2 on to obj1
        $P.extendSafe = function (obj1, obj2) {
            var key;
            for (key in obj2) {
                if (obj2.hasOwnProperty(key)) {
                    if (obj1.hasOwnProperty(key)) {
                        throw "naming collision: " + key;
                    }
                    obj1[key] = obj2[key];
                }
            }
            return obj1;
        };
    
        // if incorrect types are passed, it will return an empty array
        // arrays only
        $P.filter = function (arr, func, con) {
            var results = [];
            if ((arr == null) || (typeof func !== 'function')) {
                return results;
            }
            if (nativeFilter && arr.filter === nativeFilter) {
                return arr.filter(func, con);
            }
            $P.someIndex(arr, function (val, ind, arr) {
                if (func.call(con, val, ind, arr)) {
                    results.push(val);
                }
            });
            return results;
        };
    
        $P.clone = function (obj) {
            return $P.extend({}, obj);
        };
    
    /******************************************************************************/
    // GENERAL
    
        $P.someIndex(['Arguments', 'Function', 'String', 'Number',
            'Date', 'RegExp', 'Object'], function (val) {
            $P['is' + val] = function (obj) {
                return $P.isType(val, obj);
            };
        });
    
    /******************************************************************************/
    // STRINGS
    
        $P.addU = function (str, suf) {
            return str + '_' + suf;
        };
    
        $P.removeU = function (str) {
            if (typeof str !== 'string' || str === "") {
                return false;
            }
            return str.slice(str, str.lastIndexOf("_"));
        };
    
        $P.removeSuffix = function (str, len) {
            if (typeof str !== 'string' || str === "") {
                return false;
            }
            return str.slice(0, -len);
        };
    
    /******************************************************************************/
    // TESTING
    
        // equivalent to IIFE but "nicer" syntax
        $P.runTest = (function () {
            var tests = {};
            return function (name, arr, func) {
                tests[name] = func.apply(this, arr);
            };
        }());
    
    /******************************************************************************/
    // COMPLETE
    
        self[$R.g] = $P.extendSafe($P, {});
    
    // this will hold the global object - window or exports
    }(this));
anon