UNPKG

bat-ria

Version:

RIA extension for Brand Ads Team

387 lines (361 loc) 11.7 kB
/** * @file underscore扩展 * @author Justineo(justice360@gmail.com) */ define(function (require) { var u = require('underscore'); /** * underscore扩展模块 * * @singleton */ var util = {}; /** * 清理对象中无用的键值对 * * 默认会去除所有值为`null`、`undefined`以及空字符串`""`的键值对 * * 如果提供了`defaults`参数,则额外去除值与`defaults`的同名属性相同的键值对 * * @param {Object} object 输入的对象 * @param {Object} [defaults] 用于提供属性默认值的参照对象 * @param {boolean} [deep=false] 是否深度清理,即遇到属性值为对象继续递归清理 * @return {Object} 清理后的新对象 */ util.purify = function purify(object, defaults, deep) { defaults = defaults || {}; var purifiedObject = {}; u.each( object, function (value, key) { var isDefaultNull = value == null || value === ''; var isInDefaults = defaults.hasOwnProperty(key) && defaults[key] === value; if (!isDefaultNull && !isInDefaults) { if (deep && typeof value === 'object') { purifiedObject[key] = purify(value, defaults[key], deep); } else { purifiedObject[key] = value; } } } ); return purifiedObject; }; /** * `filterObject`用来判断是否过滤的方法 * @callback underscore~filterCallback * @param {Object} obj 需要过滤的对象 * @param {string} key 对应的键 * @return {boolean} 是否过滤,如为falsy值则过滤 */ /** * 根据指定条件过滤对象中的键值对 * * @param {Object} obj 输入的对象 * @param {filterCallback} predicate 判断是否要保留某键值对,返回falsy value则过滤 * @param {*} [context] 判断函数的`this` * @return {Object} 过滤的结果 */ util.filterObject = function (obj, predicate, context) { var result = {}; if (obj == null) { return result; } u.each(obj, function (value, key) { if (predicate.call(context, value, key, obj)) { result[key] = value; } }); return result; }; /** * `mapObject`用来处理映射逻辑的方法 * @callback underscore~mapObjectCallback * @param {*} original 处理前值 * @return {*} 处理后结果 */ /** * 根据指定的映射关系修改对象的键值 * * @param {Object} obj 输入的对象 * @param {mapObjectCallback} iterator 每个键值的映射函数 * @param {*} [context] 判断函数的`this` * @return {Object} context 映射函数的this */ util.mapObject = function (obj, iterator, context) { var result = {}; if (obj == null) { return result; } u.each(obj, function (value, key) { result[key] = iterator.call(context, value); }); return result; }; /** * 根据指定的映射关系修改对象的键名 * * 如果键名不在给定的映射关系中,保留原名 * * @param {Object} obj 输入的对象 * @param {Object.<string, string>} map 键名的映射关系 * @return {Object} 转换过的新对象 */ util.mapKey = function (obj, map) { var result = {}; if (obj == null) { return result; } u.each(obj, function (value, key) { if (map[key]) { result[map[key]] = value; } else { result[key] = value; } }); return result; }; /** * 去除字符串首尾空格 * * @param {string} s 输入字符串 * @return {string} */ util.trim = function (s) { return s.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); }; /** * 将一个符合一定规则的字符串转成`PascalCase`形式 * * 输入字符串必须以空格、横线`-`或下划线`_`分割各单词,否则无法分析 * * @param {string} s 输入的字符串 * @return {string} */ util.pascalize = function (s) { s = s + ''; if (/^[A-Z\-_]+$/.test(s)) { s = s.toLowerCase(); } s = s.replace( /[\s-_]+(.)/g, function (w, c) { return c.toUpperCase(); } ); s = s.charAt(0).toUpperCase() + s.slice(1); return s; }; /** * 将一个符合一定规则的字符串转成`camelCase`形式 * * 此方法是将{@link util#pascalize}方法的输出首字母变为小写 * * @param {string} s 输入的字符串 * @return {string} */ util.camelize = function (s) { s = util.pascalize(s); return s.charAt(0).toLowerCase() + s.slice(1); }; /** * 将一个符合规则的字符串转成`split-by-dash`的横线分割形式 * * 具体规则参考{@link util#pascalize}方法的说明 * * 在此方法中,如果字符串出现多个连续的大写字母,则会将除最后一个字符以外的子串 * 转成小写字母后再进行分割,因为连续的大写字母通常表示一个单词的缩写,不应当拆分, * 如`encodeURIComponent`在经过此方法处理后会变为`encode-uri-component`, * 而不是`encode-u-r-i-component`,前者拥有更好的可读性 * * @param {string} s 输入的字符串 * @return {string} */ util.dasherize = function (s) { s = util.pascalize(s); // 这里把xABCDx这种连续的大写,转成xAbcDx这种形式。 // 如果`encodeURIComponent`,会变成`encodeUriComponent`, // 然后加横线后就是`encode-uri-component`得到正确的结果 var keepLast = false; if (/[A-Z]{2,}$/.test(s)) { // 如果连续的大写出现在最后,则不单独处理最后的字母 keepLast = true; } s = s.replace( /[A-Z]{2,}/g, function (match) { return match.charAt(0) + (keepLast ? match.slice(1).toLowerCase() : (match.slice(1, -1).toLowerCase() + match.charAt(match.length - 1)) ); } ); // 大写字符之间用横线连起来 s = s.replace( /[A-Z]/g, function (match) { return '-' + match.toLowerCase(); } ); if (s.charAt(0) === '-') { s = s.slice(1); } if (s.charAt(s.length - 1) === '-') { s = s.slice(0, -1); } return s; }; /** * 将一个符合规则的字符串转成`THIS_IS_A_CONST`的常量形式 * * 具体规则参考{@link util#pascalize}方法的说明 * * @param {string} s 输入的字符串 * @return {string} */ util.constanize = function (s) { s = util.dasherize(s); s = s.replace(/-/g, '_'); return s.toUpperCase(); }; /** * 将一个单词转为复数 * * 如果单词结尾为`y`,则转为`ies`,其它情况下简单地加上`s` * * @param {string} s 输入的字符串 * @return {string} */ util.pluralize = function (s) { return s.replace(/y$/, 'ie') + 's'; }; /** * 格式化数字 * * @param {number} number 输入的数字 * @param {number} [decimals=0] 保留小数位数 * @param {string} [emptyValue=""] 当输入为空或不是数字时的返回内容,会加前缀 * @param {string} [prefix=""] 返回的字符串的前缀 * @return {string} */ util.formatNumber = function (number, decimals, emptyValue, prefix) { // 共6个重载: // // - `formatNumber(s)` // - `formatNumber(s, emptyValue)` // - `formatNumber(s, emptyValue, prefix)` // - `formatNumber(s, decimals)` // - `formatNumber(s, decimals, emptyValue)` // - `formatNumber(s, decimals, emptyValue, prefix)` // // 主要看第2个参数的类型,不是数字的话参数往前移1个 if (typeof arguments[1] !== 'number') { prefix = arguments[2]; emptyValue = arguments[1]; decimals = 0; } prefix = prefix || ''; emptyValue = emptyValue || ''; if (number == null || isNaN(number)) { return prefix + emptyValue; } number = parseFloat(number).toFixed(decimals); // 分为整数和小数 var parts = number.split('.'); var integer = parts[0]; var decimal = parts[1]; // 加上千位分隔 integer = integer.replace(/(\d)(?=(?:\d{3})+$)/g, '$1,'); // 再拼起来 var result = prefix + integer; if (decimal) { result += '.' + decimal; } return result; }; /** * 当字符串未达到预期长度时,在前方填充补齐字符 * * @param {string} s 输入字符串 * @param {string} padding 补齐用的字符,只能是一个字符 * @param {number} length 补齐后的长度 * @return {string} */ util.pad = function (s, padding, length) { s = s + ''; var padLength = length - s.length; if (padLength > 0) { var left = new Array(padLength + 1).join(padding); return left + s; } else { return s; } }; /** * 当字符串未达到预期长度时,在后方填充补齐字符 * * @param {string} s 输入字符串 * @param {string} padding 补齐用的字符,只能是一个字符 * @param {number} length 补齐后的长度 * @return {string} */ util.padRight = function (s, padding, length) { s = s + ''; var padLength = length - s.length; if (padLength > 0) { var right = new Array(padLength + 1).join(padding); return s + right; } else { return s; } }; /** * 深度复制一个对象 * * @param {Mixed} obj 任何对象 * @return {Mixed} 复制后的对象 */ util.deepClone = function (obj) { // 非对象以及函数就直接返回 if (!u.isObject(obj) || u.isFunction(obj)) { return obj; } if (u.isArray(obj)) { return u.map(obj, util.deepClone); } var clone = {}; u.each( obj, function (value, key) { clone[key] = util.deepClone(value); } ); return clone; }; /** * 获取指定参数的类型 * * 取自`Object.prototype.toString`的结果,比isXX方法更为准确 * * @param {Mixed} value 需要判断的参数 * @return {string} 参数类型(Object, Array, Function, ...) */ util.typeOf = function (value) { return Object.prototype.toString.call(value).slice(8, -1); }; function activate() { u.mixin(util); } return { activate: u.once(activate) }; });