lodash.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. import { _decorator } from "cc";
  2. const { ccclass } = _decorator;
  3. @ccclass("lodash")
  4. export class lodash {
  5. /* class member could be defined like this */
  6. // dummy = '';
  7. /**
  8. * 遍历 collection(集合)元素,返回 predicate(断言函数)第一个返回真值的第一个元素
  9. * @param {any} collection 一个用来迭代的集合
  10. * @param {Function} predicate 每次迭代调用的函数。
  11. * @returns 返回匹配元素,否则返回 undefined。
  12. */
  13. public static find (collection: any, predicate: Function) {
  14. var result;
  15. if (!Array.isArray(collection)) {
  16. collection = lodash._toArray(collection);
  17. }
  18. result = collection.filter(predicate);
  19. if (result.length) {
  20. return result[0];
  21. }
  22. return undefined;
  23. }
  24. /**
  25. * 调用 iteratee 遍历 collection(集合) 中的每个元素
  26. * @param {any} collection 一个用来迭代的集合
  27. * @param {Function} iteratee 每次迭代调用的函数。
  28. */
  29. public static forEach(collection: any, iteratee: any) {
  30. if (!Array.isArray(collection)) {
  31. var array = lodash._toArrayKey(collection);
  32. array.forEach(function (value: any, index: number, arr: any[]) {
  33. var key1 = value['key'];
  34. var value1 = value['value'];
  35. iteratee(value1, key1, collection);
  36. });
  37. } else {
  38. collection.forEach(iteratee);
  39. }
  40. }
  41. /**
  42. * 深度拷贝
  43. * @param {any} sObj 拷贝的对象
  44. * @returns
  45. */
  46. public static cloneDeep(sObj: any) {
  47. if (sObj === null || typeof sObj !== "object") {
  48. return sObj;
  49. }
  50. let s: any = {};
  51. if (sObj.constructor === Array) {
  52. s = [];
  53. }
  54. for (let i in sObj) {
  55. if (sObj.hasOwnProperty(i)) {
  56. s[i] = lodash.cloneDeep(sObj[i]);
  57. }
  58. }
  59. return s;
  60. }
  61. /**
  62. * 创建一个数组, value(值) 是 iteratee(迭代函数)遍历 collection(集合)中的每个元素后返回的结果。
  63. * @param {Array|Object} collection 一个用来迭代的集合.
  64. * @param {Function} predicate 一个迭代函数,用来转换key(键
  65. * @returns {Array} 返回一个组成集合数组
  66. */
  67. public static map(collection: any, iteratee: any) {
  68. if (!Array.isArray(collection)) {
  69. collection = lodash._toArray(collection);
  70. }
  71. let arr: any[] = [];
  72. collection.forEach(function (value: any, index: number, array: []) {
  73. arr.push(iteratee(value, index, array));
  74. });
  75. return arr;
  76. }
  77. /**
  78. *
  79. * @param srcObj
  80. * @returns
  81. */
  82. private static _toArrayKey(srcObj: { [x: string]: any; hasOwnProperty: (arg0: string) => any; }) {
  83. var resultArr = [];
  84. // to array
  85. for (var key in srcObj) {
  86. if (!srcObj.hasOwnProperty(key)) {
  87. continue;
  88. }
  89. resultArr.push({ key: key, value: srcObj[key] });
  90. }
  91. return resultArr;
  92. }
  93. private static _toArray(srcObj: any) {
  94. let resultArr: any[] = [];
  95. // to array
  96. for (var key in srcObj) {
  97. if (!srcObj.hasOwnProperty(key)) {
  98. continue;
  99. }
  100. resultArr.push(srcObj[key]);
  101. }
  102. return resultArr;
  103. }
  104. /**
  105. * 遍历 collection(集合)元素,返回 predicate(断言函数)返回真值 的所有元素的数组。
  106. * @param {Array|Object} collection 一个用来迭代的集合.
  107. * @param {Function} predicate 一个迭代函数,用来转换key(键
  108. * @returns 返回一个新的过滤后的数组。
  109. */
  110. public static filter(collection: any, iteratees: Function) {
  111. if (!Array.isArray(collection)) {
  112. collection = lodash._toArray(collection);
  113. }
  114. return collection.filter(iteratees);
  115. }
  116. /**
  117. * 执行深比较来确定两者的值是否相等。
  118. * @param {any}x
  119. * @param {any}y
  120. * @returns {boolean} 如果 两个值完全相同,那么返回 true,否则返回 false。
  121. */
  122. public static isEqual(x: any, y: any): boolean {
  123. var in1 = x instanceof Object;
  124. var in2 = y instanceof Object;
  125. if (!in1 || !in2) {
  126. return x === y;
  127. }
  128. if (Object.keys(x).length !== Object.keys(y).length) {
  129. return false;
  130. }
  131. for (var p in x) {
  132. var a = x[p] instanceof Object;
  133. var b = y[p] instanceof Object;
  134. if (a && b) {
  135. return lodash.isEqual(x[p], y[p]);
  136. } else if (x[p] !== y[p]) {
  137. return false;
  138. }
  139. }
  140. return true;
  141. }
  142. /**
  143. * 接收一个要移除值的数组。
  144. * @param {Array} array 修改的数组
  145. * @param {Array} value 移除值的数组
  146. * @param {Function} comparator comparator(比较器)调用每个元素。
  147. * @returns
  148. */
  149. public static pullAllWith(array: any[], value: any[], comparator: Function) {
  150. value.forEach(function (item) {
  151. var res = array.filter(function (n) {
  152. return comparator(n, item);
  153. });
  154. res.forEach(function (item) {
  155. var index = array.indexOf(item);
  156. if (array.indexOf(item) !== -1) {
  157. array.splice(index, 1);
  158. }
  159. });
  160. });
  161. return array;
  162. }
  163. /**
  164. * 返回当前时间戳
  165. * @returns
  166. */
  167. public static now() {
  168. return Date.now();
  169. }
  170. /**
  171. * 接收一个要移除值的数组。
  172. * @param {Array} array 修改的数组
  173. * @param {Array} value 移除值的数组
  174. * @returns
  175. */
  176. public static pullAll(array: any[], value: any) {
  177. value.forEach(function (item: any) {
  178. var index = array.indexOf(item);
  179. if (array.indexOf(item) !== -1) {
  180. array.splice(index, 1);
  181. }
  182. });
  183. return array;
  184. }
  185. /**
  186. * 从右到左遍历集合中每一个元素的。
  187. * @param {Array|Object} collection 一个用来迭代的集合.
  188. * @param {Function} predicate 一个迭代函数
  189. */
  190. public static forEachRight(collection: [] | {}, iteratee: Function) {
  191. if (!Array.isArray(collection)) {
  192. collection = lodash._toArray(collection);
  193. }
  194. //@ts-ignore
  195. for (var i = collection.length - 1; i >= 0; i--) {
  196. //@ts-ignore
  197. var ret = iteratee(collection[i]);
  198. if (!ret) break;
  199. }
  200. }
  201. /**
  202. * 检查字符串string是否以 target 开头。
  203. * @param {string} str 要检索的字符串。
  204. * @param {string}target 要检查的字符串。
  205. * @param {number}position 检索的位置。
  206. * @returns
  207. */
  208. public static startsWith(str: string, target: string, position: number) {
  209. str = str.substr(position);
  210. return str.startsWith(target);
  211. }
  212. /**
  213. * 检查字符串string是否以 target 结束。
  214. * @param {string} str 要检索的字符串。
  215. * @param {string}target 要检查的字符串。
  216. * @param {number}position 检索的位置。
  217. * @returns
  218. */
  219. public static endsWith(str: string, target: string, position: number) {
  220. str = str.substr(position);
  221. return str.endsWith(target);
  222. }
  223. /**
  224. * 移除数组中predicate(断言)返回为真值的所有元素
  225. * @param {Array} array 一个用来迭代的集合.
  226. * @param {Function} predicate 一个迭代函数
  227. * @returns
  228. */
  229. public static remove(array: any[], predicate: Function) {
  230. var result: any[] = [];
  231. var indexes: any[] = [];
  232. array.forEach(function (item, index) {
  233. if (predicate(item)) {
  234. result.push(item);
  235. indexes.push(index);
  236. }
  237. });
  238. lodash._basePullAt(array, indexes);
  239. return result;
  240. }
  241. private static _basePullAt(array: any[], indexes: any[]) {
  242. var length = array ? indexes.length : 0;
  243. var lastIndex = length - 1;
  244. var previous;
  245. while (length--) {
  246. var index = indexes[length];
  247. if (length === lastIndex || index !== previous) {
  248. previous = index;
  249. Array.prototype.splice.call(array, index, 1);
  250. }
  251. }
  252. return array;
  253. }
  254. /**
  255. * 返回第一个通过 predicate 判断为真值的元素的索引值
  256. * @param {Array} array 一个用来迭代的集合.
  257. * @param {Function} predicate 一个迭代函数
  258. * @param {number} fromIndex 开始查找索引值
  259. * @returns
  260. */
  261. public static findIndex(array: any[], predicate: Function, fromIndex: number) {
  262. array = array.slice(fromIndex);
  263. var i;
  264. if (typeof predicate === "function") {
  265. for (i = 0; i < array.length; i++) {
  266. if (predicate(array[i])) {
  267. return i;
  268. }
  269. }
  270. } else if (Array.isArray(predicate)) {
  271. for (i = 0; i < array.length; i++) {
  272. var key = predicate[0];
  273. var vaule = true;
  274. //@ts-ignore
  275. if (predicate.length > 1) {
  276. vaule = predicate[1];
  277. }
  278. if (array[i][key] === vaule) {
  279. return i;
  280. }
  281. }
  282. } else {
  283. for (i = 0; i < array.length; i++) {
  284. if (array[i] === predicate) {
  285. return i;
  286. }
  287. }
  288. }
  289. return -1;
  290. }
  291. /**
  292. * 创建一个新数组,将array与任何数组 或 值连接在一起。
  293. * @returns
  294. */
  295. public static concat() {
  296. var length = arguments.length;
  297. if (!length) {
  298. return [];
  299. }
  300. var array = arguments[0];
  301. var index = 1;
  302. while (index < length) {
  303. array = array.concat(arguments[index]);
  304. index++;
  305. }
  306. return array;
  307. }
  308. /**
  309. * 检查 value 是否是原始Number数值型 或者 对象。
  310. * @param {any }value
  311. * @returns
  312. */
  313. public static isNumber(value: any) {
  314. return typeof value === 'number';
  315. }
  316. /**
  317. * 返回首次 value 在数组array中被找到的 索引值
  318. * @param {Array}array
  319. * @param {any}value
  320. * @param {number} fromIndex
  321. * @returns
  322. */
  323. public static indexOf(array: any[], value: any, fromIndex: number) {
  324. array = array.slice(fromIndex);
  325. return array.indexOf(value);
  326. }
  327. /**
  328. * 将 array 中的所有元素转换为由 separator 分隔的字符串。
  329. * @param {any} array 要转换的数组
  330. * @param {string} separator 分隔元素。
  331. * @returns
  332. */
  333. public static join(array: any[], separator: string) {
  334. if (array === null) return '';
  335. var result = '';
  336. array.forEach(function (item) {
  337. result += item + separator;
  338. });
  339. return result.substr(0, result.length - 1);
  340. }
  341. /**
  342. * 根据separator 拆分字符串string。
  343. * @param {string} str 要转换的数组
  344. * @param {RegExp|string} separator 分隔元素。
  345. * @param {number} limit 限制结果的数量。
  346. * @returns
  347. */
  348. public static split(str: string, separator: RegExp|string, limit: number) {
  349. return str.split(separator, limit);
  350. }
  351. /**
  352. * 计算 array 中的最大值。 如果 array 是 空的或者假值将会返回 undefined。
  353. * @param {Array}array
  354. * @returns
  355. */
  356. public static max(array: any[]) {
  357. if (array && array.length) {
  358. var result;
  359. for (var i = 0; i < array.length; i++) {
  360. if (i === 0) {
  361. result = array[0];
  362. } else if (result < array[i]) {
  363. result = array[i];
  364. }
  365. }
  366. return result;
  367. }
  368. return undefined;
  369. }
  370. /**
  371. * 创建一个切片数组,去除array前面的n个元素。(n默认值为1。)
  372. * @param {Array}array : 要查询的数组。
  373. * @param {number}n 要去除的元素个数。
  374. * @returns
  375. */
  376. public static drop(array: any[], n: number) {
  377. var length = array === null ? 0 : array.length;
  378. if (!length) {
  379. return [];
  380. }
  381. return array.slice(n);
  382. }
  383. /**
  384. * 将array递归为一维数组。
  385. * @param {Array} arr
  386. * @returns
  387. */
  388. public static flattenDeep(arr: any[]): any {
  389. return arr.reduce(function (prev: any[], cur: any[]) {
  390. return prev.concat(Array.isArray(cur) ? lodash.flattenDeep(cur) : cur);
  391. }, [ ]);
  392. }
  393. /**
  394. * 创建一个去重后的array数组副本。使用了SameValueZero 做等值比较。只有第一次出现的元素才会被保留。
  395. * @param {Array} array
  396. * @returns
  397. */
  398. public static uniq(array: any[]) {
  399. let result: any[] = [];
  400. array.forEach(function (item) {
  401. if (result.indexOf(item) === -1) {
  402. result.push(item);
  403. }
  404. });
  405. return result;
  406. }
  407. /**
  408. * 检查 value 是否是 NaN。
  409. * @param {any}value
  410. * @returns
  411. */
  412. public static isNaN(value: any) {
  413. // An `NaN` primitive is the only value that is not equal to itself.
  414. // Perform the `toStringTag` check first to avoid errors with some
  415. // ActiveX objects in IE.
  416. return lodash.isNumber(value) && value !== +value;
  417. }
  418. /**
  419. * 将数组(array)拆分成多个 size 长度的区块,并将这些区块组成一个新数组
  420. * @param {Array}array
  421. * @param {number}size
  422. * @returns
  423. */
  424. public static chunk(array: any[], size: number) {
  425. var length = array === null ? 0 : array.length;
  426. if (!length || size < 1) {
  427. return [];
  428. }
  429. var result = [];
  430. while (array.length > size) {
  431. result.push(array.slice(0, size));
  432. array = array.slice(size);
  433. }
  434. result.push(array);
  435. return result;
  436. }
  437. /**
  438. * 转换 value 为一个有限数字
  439. * @param {any} value
  440. * @returns
  441. */
  442. public static toFinite(value: any) {
  443. var INFINITY = 1 / 0;
  444. var MAX_INTEGER = 1.7976931348623157e+308;
  445. if (!value) {
  446. return value === 0 ? value : 0;
  447. }
  448. value = Number(value);
  449. if (value === INFINITY || value === -INFINITY) {
  450. var sign = (value < 0 ? -1 : 1);
  451. return sign * MAX_INTEGER;
  452. }
  453. return value === value ? value : 0;
  454. }
  455. /**
  456. * 判断是否为对象
  457. * @param {any}value
  458. * @returns {boolean}
  459. */
  460. public static isObject(value: any) {
  461. var type = typeof value;
  462. return value !== null && (type === 'object' || type === 'function');
  463. }
  464. public static MAX_SAFE_INTEGER = 9007199254740991;
  465. /**
  466. *
  467. * @param value
  468. * @returns
  469. */
  470. public static isLength(value: any) {
  471. return typeof value === 'number' &&
  472. value > -1 && value % 1 === 0 && value <= lodash.MAX_SAFE_INTEGER;
  473. }
  474. public static _isArrayLike(value: []) {
  475. return value !== null && lodash.isLength(value.length) /*&& !isFunction(value)*/;
  476. }
  477. /**
  478. * 返回数组总符合条件的最大值
  479. * @param {Array} array 一个用来迭代的集合.
  480. * @param {Function} predicate 一个迭代函数
  481. * @returns {Object} 返回最大值
  482. */
  483. public static maxBy(array: any[], predicate: Function) {
  484. if (array && array.length) {
  485. var result;
  486. var objResult;
  487. for (var i = 0; i < array.length; i++) {
  488. if (i === 0) {
  489. result = predicate(array[0]);
  490. objResult = array[0];
  491. } else if (result < array[i]) {
  492. result = (array[i]);
  493. objResult = array[i];
  494. }
  495. }
  496. return objResult;
  497. }
  498. return undefined;
  499. }
  500. /**
  501. * 返回数组总符合条件的最小值
  502. * @param {Array} array 一个用来迭代的集合.
  503. * @param {Function} predicate 一个迭代函数
  504. * @returns {Object} 返回最小值
  505. */
  506. public static minBy(array: any[], predicate: Function) {
  507. if (array && array.length) {
  508. let result;
  509. let objResult;
  510. for (var i = 0; i < array.length; i++) {
  511. if (i === 0) {
  512. result = predicate(array[0]);
  513. objResult = array[0];
  514. } else if (result > array[i]) {
  515. result = predicate(array[i]);
  516. objResult = array[i];
  517. }
  518. }
  519. return objResult;
  520. }
  521. return undefined;
  522. }
  523. /**
  524. * 返回复合迭代函数的总和
  525. * @param {Array|Object} collection 一个用来迭代的集合.
  526. * @param {Function} predicate 一个迭代函数
  527. * @returns {Object} 返回总和
  528. */
  529. public static sumBy(collection: [] | {}, predicate: Function) {
  530. let sum: number = 0;
  531. for (let key in collection) {
  532. //@ts-ignore
  533. sum += predicate(collection[key]);
  534. }
  535. return sum;
  536. }
  537. /**
  538. * 返回复合迭代函数的次数
  539. * @param {Array|Object} collection 一个用来迭代的集合.
  540. * @param {Function} predicate 一个迭代函数,用来转换key(键
  541. * @returns {Object} 返回一个组成集合对象
  542. */
  543. public static countBy(collection: [] | {}, predicate: Function) {
  544. let objRet: {[key: string]: number} = {};
  545. for (let key in collection) {
  546. let value: any = predicate(key);
  547. if (objRet.hasOwnProperty(value)) {
  548. objRet[value] += 1;
  549. } else {
  550. objRet[value] = 1;
  551. }
  552. }
  553. return objRet;
  554. }
  555. }