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;
$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;
};
}());
$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);
};
$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);
};
$P.someIndex(['Arguments', 'Function', 'String', 'Number',
'Date', 'RegExp', 'Object'], function (val) {
$P['is' + val] = function (obj) {
return $P.isType(val, obj);
};
});
$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);
};
// equivalent to IIFE but "nicer" syntax
$P.runTest = (function () {
var tests = {};
return function (name, arr, func) {
tests[name] = func.apply(this, arr);
};
}());
self[$R.g] = $P.extendSafe($P, {});
// this will hold the global object - window or exports
}(this));