1. 如何判断一个对象里面的属性值都为空

  1. const applyData = {
  2. name:'',
  3. age:''
  4. }
  5. let result = !Object.values(applyData).every(item => item === '');
  6. console.log(result) //false
  1. // 获取指定名称的cookie的值
  2. const getCookie = (objName) => {
  3. var cookies = document.cookie.split('; ')
  4. for (var i = 0; i < cookies.length; i++) {
  5. var temp = cookies[i].trim().split('=')
  6. if (temp[0] === objName) {
  7. return temp[1]
  8. }
  9. }
  10. return ''
  11. }
  12. const setCookie = (name, value, seconds) => {
  13. seconds = seconds || 0 // seconds有值就直接赋值,没有为0,这个跟php不一样
  14. var expires = ''
  15. if (seconds !== 0) {
  16. // 设置cookie生存时间
  17. var date = new Date()
  18. date.setTime(date.getTime() + seconds * 1000)
  19. expires = '; expires=' + date.toGMTString()
  20. }
  21. document.cookie = name + '=' + escape(value) + expires + '; path=/' // 转码并赋值
  22. }
  23. const clearCookie = (name) => {
  24. setCookie(name, '', -1)
  25. }
  26. const formatTime = (dt) => {
  27. var h = dt.getHours()
  28. var m = dt.getMinutes()
  29. var s = dt.getSeconds()
  30. var r = ''
  31. if (h > 0) {
  32. r += (h > 9 ? h.toString() : '0' + h.toString()) + ':'
  33. } else {
  34. r += '00' + ':'
  35. }
  36. r += (m > 9 ? m.toString() : '0' + m.toString()) + ':'
  37. r += s > 9 ? s.toString() : '0' + s.toString()
  38. return r
  39. }
  40. const formatMonth = (inputTime) => {
  41. var date = new Date(inputTime)
  42. var y = date.getFullYear()
  43. var m = date.getMonth() + 1
  44. m = m < 10 ? '0' + m : m
  45. return y + '-' + m
  46. }
  47. const formatDate = (inputTime) => {
  48. var date = new Date(inputTime)
  49. var y = date.getFullYear()
  50. var m = date.getMonth() + 1
  51. m = m < 10 ? '0' + m : m
  52. var d = date.getDate()
  53. d = d < 10 ? '0' + d : d
  54. return y + '-' + m + '-' + d
  55. }
  56. const formatDateTime = (inputTime) => {
  57. var date = new Date(inputTime)
  58. var y = date.getFullYear()
  59. var m = date.getMonth() + 1
  60. m = m < 10 ? '0' + m : m
  61. var d = date.getDate()
  62. d = d < 10 ? '0' + d : d
  63. var h = date.getHours()
  64. h = h < 10 ? '0' + h : h
  65. var minute = date.getMinutes()
  66. var second = date.getSeconds()
  67. minute = minute < 10 ? '0' + minute : minute
  68. second = second < 10 ? '0' + second : second
  69. return y + '-' + m + '-' + d + ' ' + h + ':' + minute + ':' + second
  70. }
  71. const formatDateRange = (inputTime) => {
  72. var date = new Date(inputTime)
  73. var y = date.getFullYear()
  74. var m = date.getMonth() + 1
  75. m = m < 10 ? '0' + m : m
  76. var start = y + '-' + m + '-01'
  77. var lastDay = new Date(y, m, 0)
  78. var d = lastDay.getDate()
  79. var end = y + '-' + m + '-' + d
  80. return [start, end]
  81. }
  82. const capitalize = (str) => {
  83. return str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase())
  84. }
  85. const monthDiff = (daterange) => {
  86. var start = daterange[0]
  87. var end = daterange[1]
  88. var result = []
  89. if (start.split('-')[0] === end.split('-')[0]) {
  90. for (var month = start.split('-')[1]; month <= end.split('-')[1]; month++) {
  91. result.push({
  92. key: month,
  93. value: start.split('-')[0] + '-' + month
  94. })
  95. }
  96. } else {
  97. for (month = start.split('-')[1]; month <= 12; month++) {
  98. result.push({
  99. key: month,
  100. value: start.split('-')[0] + '-' + month
  101. })
  102. }
  103. for (month = 1; month <= end.split('-')[1]; month++) {
  104. result.push({
  105. key: String(month),
  106. value: end.split('-')[0] + '-' + month
  107. })
  108. }
  109. }
  110. return result
  111. }
  112. // 颜色格式 hex rgba
  113. const hexToRgba = (bgColor, precent) => {
  114. let color = bgColor.slice(1) // 去掉'#'
  115. let rgba = [
  116. parseInt('0x' + color.slice(0, 2)),
  117. parseInt('0x' + color.slice(2, 4)),
  118. parseInt('0x' + color.slice(4, 6)),
  119. precent
  120. ]
  121. return 'rgba(' + rgba.toString() + ')'
  122. }
  123. const getColor = (index, precent) => {
  124. if (precent <= 20) precent = 20
  125. else if (precent > 20 && precent <= 40) precent = 40
  126. else if (precent > 40 && precent <= 60) precent = 60
  127. else if (precent > 60 && precent <= 80) precent = 80
  128. else precent = 100
  129. precent /= 100
  130. // ['#FADBCA', '#E17761'], ['#FFFBCC', '#FFEE66'], ['#FDE6CA', '#F69F62'], ['#E1FBF5', '#CFF5F2'], ['#E3E3F3', '#A9A9F6'], ['#EBFCED', '#C0F0D0'], ['#ECF9F8', '#BAD8DB'], ['#F8FCCC', '#E0F266'], ['#F6E0FA', '#D09DE3'], ['#E9FDD6', '#AAF383'], ['#E1FAF0', '#9EE1D4'], ['#FEF9DB', '#FEE894'], ['#FEF8EB', '#FCE3C2'], ['#FDEDD9', '#F8B98C'], ['#FEEECD', '#F9BD69'], ['#FADBCA', '#E17761'], ['#FFFBCC', '#FFEE66'], ['#FDE6CA', '#F69F62']
  131. var allColor = ['#fccde2', '#c5e3f6']
  132. // return hexToRgba(allColor[index % 18][1], precent)
  133. return hexToRgba(allColor[index % 2], precent)
  134. }
  135. // 对象转化为数组
  136. const jsonToArray = (obj) => {
  137. let arr = []
  138. for (let i in obj) {
  139. let o = {}
  140. o[i] = obj[i]
  141. arr.push(o)
  142. }
  143. return arr
  144. }
  145. // 表格相同项进行合并展示
  146. const dealRow = (arr, size) => {
  147. let flag = {
  148. projectId: '',
  149. index: 0,
  150. length: 1
  151. }
  152. arr.forEach((item, index) => {
  153. if (flag.projectId === item.projectId) {
  154. flag.length += 1
  155. } else {
  156. if (flag.projectId) {
  157. arr[flag.index].colspan = 1
  158. arr[flag.index].rowspan = flag.length
  159. for (let i = 1; i < flag.length; i++) {
  160. if ((flag.index + i) % size === 0) {
  161. arr[flag.index + i].colspan = 1
  162. arr[flag.index + i].rowspan = flag.length - i
  163. } else {
  164. arr[flag.index + i].colspan = 0
  165. arr[flag.index + i].rowspan = 0
  166. }
  167. }
  168. flag.projectId = item.projectId
  169. flag.index = index
  170. flag.length = 1
  171. arr[index].colspan = 1
  172. arr[index].rowspan = flag.length
  173. } else {
  174. flag.projectId = item.projectId
  175. // 考虑只筛选出一条任务的情况
  176. if (arr[flag.index].colspan === 0 || arr[flag.index].rowspan === 0) {
  177. arr[flag.index].colspan = 1
  178. arr[flag.index].rowspan = flag.length
  179. }
  180. }
  181. }
  182. if (index === arr.length - 1 && flag.length > 1) {
  183. arr[index - flag.length + 1].colspan = 1
  184. arr[index - flag.length + 1].rowspan = flag.length
  185. for (let i = 0; i < flag.length - 1; i++) {
  186. arr[index - i].colspan = 0
  187. arr[index - i].rowspan = 0
  188. if ((flag.index + i + 1) % size === 0) {
  189. arr[flag.index + i + 1].colspan = 1
  190. arr[flag.index + i + 1].rowspan = flag.length - i + 1
  191. }
  192. }
  193. }
  194. })
  195. return arr
  196. }
  197. // roleMap里查询对应角色的人名 arrroleMap type为对应角色
  198. const getRoleType = (arr, type) => {
  199. let result = []
  200. for (let i in arr) {
  201. if (arr[i] === type) {
  202. result.push(i)
  203. }
  204. }
  205. return result
  206. }
  207. // 遍历叠加
  208. const ReduceArray = (arr, name) => {
  209. let result = ''
  210. if(arr && arr.length) {
  211. arr.forEach(item => {
  212. result = String(item[name]) + ' '
  213. })
  214. }
  215. return result
  216. }
  217. // 时间降序排列
  218. // const compareTime = (property) => {
  219. // return function (obj1, obj2) {
  220. // var value1 = new Date(obj1[property].replace(/-/g, '/')).getTime()
  221. // var value2 = new Date(obj2[property].replace(/-/g, '/')).getTime()
  222. // return value2 - value1 // 降序
  223. // }
  224. // }
  225. // const compareTime = (arr) => {
  226. // console.log(arr)
  227. // return arr.sort((a, b) => {
  228. // return moment(b, 'DD/MM/YYYY').valueOf() - moment(a, 'DD/MM/YYYY').valueOf();
  229. // })
  230. // }
  231. // import moment from "moment"
  232. module.exports = {
  233. getCookie,
  234. setCookie,
  235. clearCookie,
  236. formatTime,
  237. formatMonth,
  238. formatDate,
  239. formatDateTime,
  240. formatDateRange,
  241. capitalize,
  242. monthDiff,
  243. hexToRgba,
  244. getColor,
  245. jsonToArray,
  246. dealRow,
  247. getRoleType,
  248. ReduceArray,
  249. // compareTime
  250. }

快速生成日期数组

  1. Array.from({ length: 12 }, (a, i) => {
  2. console.log(a)
  3. let now = new Date()
  4. now = now.setMonth(now.getMonth() - i)
  5. now = new Date(now)
  6. let index = now.toLocaleString('ja').lastIndexOf('/')
  7. return now.toLocaleString('ja').replaceAll('/', '-').slice(0, index)
  8. }).reverse(), //横坐标

数组排序

https://www.w3school.com.cn/js/js_array_sort.asp
sort() 方法是最强大的数组方法之一。

  1. var fruits = ["Banana", "Orange", "Apple", "Mango"];
  2. fruits.sort(); // 对 fruits 中的元素进行排序

数组对象排序

  1. var cars = [
  2. {type:"Volvo", year:2016},
  3. {type:"Saab", year:2001},
  4. {type:"BMW", year:2010}
  5. ];
  6. cars.sort((a, b) => return a.year - b.year);

属性是字符串:

  1. cars.sort((a, b) => {
  2. var x = a.type.toLowerCase();
  3. var y = b.type.toLowerCase();
  4. if (x < y) {return -1;}
  5. if (x > y) {return 1;}
  6. return 0;
  7. });
  1. //按时间线排序
  2. data.sort((a, b) => {
  3. var x = a.monthDate.toLowerCase()
  4. var y = b.monthDate.toLowerCase()
  5. if (x < y) {
  6. return -1
  7. }
  8. if (x > y) {
  9. return 1
  10. }
  11. return 0
  12. })

数组去重

https://segmentfault.com/a/1190000016418021
https://segmentfault.com/a/1190000021951088
测试数据

  1. var meta = [
  2. 0,
  3. '0',
  4. true,
  5. false,
  6. 'true',
  7. 'false',
  8. null,
  9. undefined,
  10. Infinity,
  11. {},
  12. [],
  13. function(){},
  14. { a: 1, b: 2 },
  15. { b: 2, a: 1 },
  16. ];
  17. var meta2 = [
  18. NaN,
  19. NaN,
  20. Infinity,
  21. {},
  22. [],
  23. function(){},
  24. { a: 1, b: 2 },
  25. { b: 2, a: 1 },
  26. ];
  27. var sourceArr = [...meta, ... Array(1000000)
  28. .fill({})
  29. .map(() => meta[Math.floor(Math.random() * meta.length)]),
  30. ...meta2];

非对象数组

1.es6最简单的方式

  1. console.time('ES6中Set耗时:');
  2. var res = [...new Set(sourceArr)];
  3. console.timeEnd('ES6中Set耗时:');
  4. // ES6中Set耗时:: 28.736328125ms
  5. console.log(res);
  6. // 打印数组长度20: [false, "true", Infinity, true, 0, [], [], {b: 2, a: 1}, {b: 2, a: 1}, {}, {}, "false", "0", null, undefined, {a: 1, b: 2}, {a: 1, b: 2}, NaN, function(){}, function(){}]

配合Array.from

  1. console.time('ES6中Set耗时:');
  2. var res = Array.from(new Set(sourceArr));
  3. console.timeEnd('ES6中Set耗时:');
  4. // ES6中Set耗时:: 28.538818359375ms
  5. console.log(res);
  6. // 打印数组长度20:[false, "true", Infinity, true, 0, [], [], {b: 2, a: 1}, {b: 2, a: 1}, {}, {}, "false", "0", null, undefined, {a: 1, b: 2}, {a: 1, b: 2}, NaN, function(){}, function(){}]

优点:简洁方便,可以区分NaN;
缺点:无法识别相同对象和数组;
简单的场景建议使用该方法进行去重。

2. 使用indexOf

  1. function unique(arr) {
  2. if (!Array.isArray(arr)) return;
  3. var result = [];
  4. for (var i = 0; i < arr.length; i++) {
  5. if (array.indexOf(arr[i]) === -1) {
  6. result.push(arr[i])
  7. }
  8. }
  9. return result;
  10. }
  11. console.time('indexOf方法耗时:');
  12. var res = unique(sourceArr);
  13. console.timeEnd('indexOf方法耗时:');
  14. // indexOf方法耗时:: 23.376953125ms
  15. console.log(res);
  16. // 打印数组长度21: [false, "true", Infinity, true, 0, [], [], {b: 2, a: 1}, {b: 2, a: 1}, {}, {}, "false", "0", null, undefined, {a: 1, b: 2}, {a: 1, b: 2}, NaN,NaN, function(){}, function(){}]

优点:ES5以下常用方法,兼容性高,易于理解;
缺点:无法区分NaN;需要特殊处理;
可以在ES6以下环境使用。

3. 使用inculdes方法

  1. function unique(arr) {
  2. if (!Array.isArray(arr)) return;
  3. var result = [];
  4. for (var i = 0; i < arr.length; i++) {
  5. if (!result.includes(arr[i])) {
  6. result.push(arr[i])
  7. }
  8. }
  9. return result;
  10. }
  11. console.time('includes方法耗时:');
  12. var res = unique(sourceArr);
  13. console.timeEnd('includes方法耗时:');
  14. // includes方法耗时:: 32.412841796875ms
  15. console.log(res);
  16. // 打印数组长度20:[false, "true", Infinity, true, 0, [], [], {b: 2, a: 1}, {b: 2, a: 1}, {}, {}, "false", "0", null, undefined, {a: 1, b: 2}, {a: 1, b: 2}, NaN, function(){}, function(){}]

优点:可以区分NaN;
缺点:ES版本要求高,和indexOf方法相比耗时较长;

4. 使用filter和indexOf方法

这种方法比较巧妙,通过判断当前的index值和查找到的index是否相等来决定是否过滤元素:

  1. function unique(arr) {
  2. if (!Array.isArray(arr)) return;
  3. return arr.filter(function(item, index, arr) {
  4. //当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
  5. return arr.indexOf(item, 0) === index;
  6. });
  7. }
  8. console.time('filter和indexOf方法耗时:');
  9. var res = unique(sourceArr);
  10. console.timeEnd('filter和indexOf方法耗时:');
  11. // includes方法耗时:: 24.135009765625ms
  12. console.log(res);
  13. // 打印数组长度19:[false, "true", Infinity, true, 0, [], [], {b: 2, a: 1}, {b: 2, a: 1}, {}, {}, "false", "0", null, undefined, {a: 1, b: 2}, {a: 1, b: 2}, function(){}, function(){}]

优点:利用高阶函数代码大大缩短;
缺点:由于indexOf无法查找到NaN,因此NaN被忽略。
这种方法很优雅,代码量也很少,但和使用Set结构去重相比还是美中不足。

5. 利用reduce+includes

同样是两个高阶函数的巧妙使用:

  1. var unique = (arr) => {
  2. if (!Array.isArray(arr)) return;
  3. return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
  4. }
  5. var res = unique(sourceArr);
  6. console.time('reduce和includes方法耗时:');
  7. var res = unique(sourceArr);
  8. console.timeEnd('reduce和includes方法耗时:');
  9. // reduce和includes方法耗时:: 100.47802734375ms
  10. console.log(res);
  11. // 打印数组长度20:[false, "true", Infinity, true, 0, [], [], {b: 2, a: 1}, {b: 2, a: 1}, {}, {}, "false", "0", null, undefined, {a: 1, b: 2}, {a: 1, b: 2}, NaN, function(){}, function(){}]

优点:利用高阶函数代码大大缩短;
缺点:ES版本要求高,速度较慢;
同样很优雅,但如果这种方法能用,同样也能用Set结构去重。

6. 利用Map结构

使用map实现:

  1. function unique(arr) {
  2. if (!Array.isArray(arr)) return;
  3. let map = new Map();
  4. let result = [];
  5. for (let i = 0; i < arr.length; i++) {
  6. if(map .has(arr[i])) {
  7. map.set(arr[i], true);
  8. } else {
  9. map.set(arr[i], false);
  10. result.push(arr[i]);
  11. }
  12. }
  13. return result;
  14. }
  15. console.time('Map结构耗时:');
  16. var res = unique(sourceArr);
  17. console.timeEnd('Map结构耗时:');
  18. // Map结构耗时:: 41.483154296875ms
  19. console.log(res);
  20. // 打印数组长度20:[false, "true", Infinity, true, 0, [], [], {b: 2, a: 1}, {b: 2, a: 1}, {}, {}, "false", "0", null, undefined, {a: 1, b: 2}, {a: 1, b: 2}, NaN, function(){}, function(){}]

相比Set结构去重消耗时间较长,不推荐使用。

7. 双层嵌套,使用splice删除重复元素

这个也比较常用,对数组进行双层遍历,挑出重复元素:

  1. function unique(arr){
  2. if (!Array.isArray(arr)) return;
  3. for(var i = 0; i < arr.length; i++) {
  4. for(var j = i + 1; j< arr.length; j++) {
  5. if(Object.is(arr[i], arr[j])) {// 第一个等同于第二个,splice方法删除第二个
  6. arr.splice(j,1);
  7. j--;
  8. }
  9. }
  10. }
  11. return arr;
  12. }
  13. console.time('双层嵌套方法耗时:');
  14. var res = unique(sourceArr);
  15. console.timeEnd('双层嵌套方法耗时:');
  16. // 双层嵌套方法耗时:: 41500.452880859375ms
  17. console.log(res);
  18. // 打印数组长度20: [false, "true", Infinity, true, 0, [], [], {b: 2, a: 1}, {b: 2, a: 1}, {}, {}, "false", "0", null, undefined, {a: 1, b: 2}, {a: 1, b: 2}, NaN, function(){}, function(){}]

优点:兼容性高。
缺点:性能低,时间复杂度高。
不推荐使用。

8. 利用sort方法

这个思路也很简单,就是利用sort方法先对数组进行排序,然后再遍历数组,将和相邻元素不相同的元素挑出来:

  1. function unique(arr) {
  2. if (!Array.isArray(arr)) return;
  3. arr = arr.sort((a, b) => a - b);
  4. var result = [arr[0]];
  5. for (var i = 1; i < arr.length; i++) {
  6. if (arr[i] !== arr[i-1]) {
  7. result.push(arr[i]);
  8. }
  9. }
  10. return result;
  11. }
  12. console.time('sort方法耗时:');
  13. var res = unique(sourceArr);
  14. console.timeEnd('sort方法耗时:');
  15. // sort方法耗时:: 936.071044921875ms
  16. console.log(res);
  17. // 数组长度357770,剩余部分省略
  18. // 打印:(357770) [Array(0), Array(0), 0...]

优点:无;
缺点:耗时长,排序后数据不可控;
不推荐使用,因为使用sort方法排序无法对数字类型0和字符串类型’0’进行排序导致大量的冗余数据存在。
上面的方法只是针对基础数据类型,对于对象数组函数不考虑,下面再看下如何去重相同的对象。

Object

下面的这种实现和利用Map结构相似,这里使用对象的key不重复的特性来实现

9. 利用hasOwnProperty和filter

使用filter和hasOwnProperty方法:

  1. function unique(arr) {
  2. if (!Array.isArray(arr)) return;
  3. var obj = {};
  4. return arr.filter(function(item, index, arr) {
  5. return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
  6. })
  7. }
  8. console.time('hasOwnProperty方法耗时:');
  9. var res = unique(sourceArr);
  10. console.timeEnd('hasOwnProperty方法耗时:');
  11. // hasOwnProperty方法耗时:: 258.528076171875ms
  12. console.log(res);
  13. // 打印数组长度13: [false, "true", Infinity, true, 0, [], {}, "false", "0", null, undefined, NaN, function(){}]

优点:代码简洁,可以区分相同对象数组函数;
缺点:版本要求高,因为要查找整个原型链因此性能较低;
该方法利用对象key不重复的特性来实现区分对象和数组,但上面是通过类型+值做key的方式,所以{a: 1, b: 2}和{}被当做了相同的数据。因此该方法也有不足。

10. 利用对象key不重复的特性

这种方法和使用Map结构类似,但key的组成有所不同:

  1. function unique(arr) {
  2. if (!Array.isArray(arr)) return;
  3. var result = [];
  4. var obj = {};
  5. for (var i = 0; i < arr.length; i++) {
  6. var key = typeof arr[i] + JSON.stringify(arr[i]) + arr[i];
  7. if (!obj[key]) {
  8. result.push(arr[i]);
  9. obj[key] = 1;
  10. } else {
  11. obj[key]++;
  12. }
  13. }
  14. return result;
  15. }
  16. console.time('对象方法耗时:');
  17. var res = unique(sourceArr);
  18. console.timeEnd('对象方法耗时:');
  19. // 对象方法耗时:: 585.744873046875ms
  20. console.log(res);
  21. // 打印数组长度15: [false, "true", Infinity, true, 0, [], {b: 2, a: 1}, {}, "false", "0", null, undefined, {a: 1, b: 2}, NaN, function(){}]

这种方法是比较成熟的,去除了重复数组和重复对象,但对于像{a: 1, b: 2}和{b: 2, a: 1}这种就无法区分,原因在于将这两个对象进行JSON.stringify()之后得到的字符串分别是{“a”:1,”b”:2}和{“b”:2,”a”:1}, 因此两个值算出的key不同。加一个判断对象是否相等的方法就好了,改写如下:

  1. function isObject(obj) {
  2. return Object.prototype.toString.call(obj) === '[object Object]';
  3. }
  4. function unique(arr) {
  5. if (!Array.isArray(arr)) return;
  6. var result = [];
  7. var obj = {};
  8. for (var i = 0; i < arr.length; i++) {
  9. // 此处加入对象和数组的判断
  10. if (Array.isArray(arr[i])) {
  11. arr[i] = arr[i].sort((a, b) => a - b);
  12. }
  13. if (isObject(arr[i])) {
  14. let newObj = {}
  15. Object.keys(arr[i]).sort().map(key => {
  16. newObj[key]= arr[i][key];
  17. });
  18. arr[i] = newObj;
  19. }
  20. var key = typeof arr[i] + JSON.stringify(arr[i]) + arr[i];
  21. if (!obj[key]) {
  22. result.push(arr[i]);
  23. obj[key] = 1;
  24. } else {
  25. obj[key]++;
  26. }
  27. }
  28. return result;
  29. }
  30. console.time('对象方法耗时:');
  31. var res = unique(sourceArr);
  32. console.timeEnd('对象方法耗时:');
  33. // 对象方法耗时:: 793.142822265625ms
  34. console.log(res);
  35. // 打印数组长度14: [false, "true", Infinity, true, 0, [], {b: 2, a: 1}, {}, "false", "0", null, undefined, NaN, function(){}]

结论

方法 优点 缺点
ES6中Set 简单优雅,速度快 基础类型推荐使用。版本要求高,不支持对象数组和NaN
使用indexOf ES5以下常用方法,兼容性高,易于理解 无法区分NaN;需要特殊处理
使用inculdes方法 可以区分NaN ES版本要求高,和indexOf方法相比耗时较长
使用filter和indexOf方法 利用高阶函数代码大大缩短; 由于indexOf无法查找到NaN,因此NaN被忽略。
利用reduce+includes 利用高阶函数代码大大缩短; ES7以上才能使用,速度较慢;
利用Map结构 无明显优点 ES6以上,
双层嵌套,使用splice删除重复元素 兼容性高 性能低,时间复杂度高,如果不使用Object.is来判断则需要对NaN特殊处理,速度极慢。
利用sort方法 耗时长,排序后数据不可控;
利用hasOwnProperty和filter :代码简洁,可以区分相同对象数组函数 版本要求高,因为要查找整个原型链因此性能较低;
利用对象key不重复的特性 优雅,数据范围广 Object推荐使用。代码比较复杂。

数组对象

  1. /**
  2. * 数组对象去重
  3. * 设置cur默认类型为数组,并且初始值为空的数组
  4. */
  5. let obj = {};
  6. arrList = arrList.reduce((cur,next) => {
  7. obj[next.value] ? "" : obj[next.value] = true && cur.push(next);
  8. return cur;
  9. },[]);
  10. // 这里得出去重后的数据
  11. console.log(arrList);

reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值

  1. 语法
  2. array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
  3. 参数 描述
  4. total 必需。初始值, 或者计算结束后的返回值。
  5. currentValue 必需。当前元素
  6. currentIndex 可选。当前元素的索引
  7. arr 可选。当前元素所属的数组对象。
  8. initialValue 可选。传递给函数的初始值

2. 冒泡排序法

  1. for (var i = 0; i < arr.length - 1; i++) {
  2. for (var j = i + 1; j < arr.length; j++) {
  3. console.log(i,j)
  4. if (arr[i].city == arr[j].city) {
  5. arr.splice(j, 1);
  6. j--; // 因为数组长度减小1,所以直接 j++ 会漏掉一个元素,所以要 j--
  7. }
  8. }
  9. }
  10. console.log(arr); // [{id: 1,city: '南京'},{id: 3,city: '杭州'},{id: 4,city: '广州'}]

3. 双重循环

  1. var newArr = [];
  2. arr.forEach((item) => {
  3. var check = newArr.every((b) => {
  4. return item.city !== b.city;
  5. })
  6. check ? newArr.push(item) : '';
  7. })
  8. console.log(newArr); // [{id: 1,city: '南京'},{id: 3,city: '杭州'},{id: 4,city: '广州'}]

4. ES6 Map对象

  1. let formatArr = () => {
  2. let map = new Map();
  3. for (let item of arr) {
  4. if (!map.has(item.city)) {
  5. map.set(item.city, item);
  6. }
  7. }
  8. return [...map.values()];
  9. }
  10. let newArr = formatArr(); // [{id: 1,city: '南京'},{id: 3,city: '杭州'},{id: 4,city: '广州'}]

js判断对象是数组类型还是对象类型

一.判断值是否是对象

  1. **toString **方式【常用】

Object.prototype.toString.call(val) === '[object Object]'// true 代表为对象
注意:这里要使用 call 方法改变作用域

  1. constructor 方式

val?.constructor === Object // true 代表为对象
这里使用了 null 传导符(?.) 以防止出错

  1. typeof 与 instanceof

typeof 与 instanceof 并不能完全判断一个值为对象
typeof 的取值有:

  1. - "undefined"——如果这个值未定义;
  2. - "boolean"——如果这个值是布尔值;
  3. - "string"——如果这个值是字符串;
  4. - "number"——如果这个值是数值;
  5. - "object"——如果这个值是对象(包括数组)或null
  6. - "function"——如果这个值是函数;
  7. - "symbol"——如果这个值是Symbol
  8. - instanceof 操作符对于数组和对象都返回 true
  9. - [] instanceof Object // true
  10. - new Object instanceof Object // true
  1. proto 方式【不推荐】

    proto属性,用来读取或设置当前对象的 prototype 对象,此属性未纳入标准,不建议使用。

val.proto === Object.prototype // true 代表为对象

  1. Object.getPrototypeOf 方式

Object.getPrototypeOf(),用来读取对象的 prototype 对象。

Object.getPrototypeOf(val) === Object.prototype // true 代表为对象

二.判断值是否为数组

  1. toString 方式

Object.prototype.toString.call(val) === ‘[object Array]’ // true 代表为数组
注意:这里要用 Object 的 toString 方法,Array 的 toString 返回的是拼接的字符串

var colors = [‘red’, ‘blue’, ‘green’];
console.log(colors.toString()); // red,blue,green

  1. Array.isArray 方法【推荐】

ES5中提供了 isArray 方法用来判断值是否为数组

Array.isArray(val) // true 代表为数组

  1. instanceof 方式

val instanceof Array // true 代表为数组
为什么 instanceof 可以用来判断数组而不可以判断对象呢?因为数组本身就是一个类似于列表的高阶对象。

  1. constructor 方式

val?.constructor === Array // true 代表为数组

  1. proto 方式【不推荐】

val.proto === Array.prototype // true 代表为数组

  1. Object.getPrototypeOf 方式

Object.getPrototypeOf(val) === Array.prototype // true 代表为数组

  1. isPrototypeOf 方式

isPrototypeOf() 方法用于测试一个对象是否存在于另一个对象的原型链上。

Array.prototype.isPrototypeOf(val) // true 代表为数组
该方式不能用来判断对象!
[

](https://blog.csdn.net/qq_39025670/article/details/110233270)

获取复杂对象指定key的value值

  1. // 判断是否为对象
  2. const isObject = (obj) => {
  3. return Object.prototype.toString.call(obj) === "[object Object]";
  4. };
  5. // 获取嵌套对象属性的值
  6. const getValue = (data, target) => {
  7. if (!data) {
  8. console.log("data不能为空");
  9. return
  10. }
  11. //数组对象
  12. if (data instanceof Array) {
  13. const datas = []
  14. for (const iterator of data) {
  15. const result = getValue(iterator, target)
  16. if (result) {
  17. datas.push(result)
  18. }
  19. continue
  20. }
  21. if (datas.length > 0) {
  22. return [...new Set(datas)];
  23. }
  24. }
  25. //普通对象
  26. if (data instanceof Object) {
  27. for (const key of Object.keys(data)) {
  28. console.log(key);
  29. if (key === target) {
  30. return data[key];
  31. }
  32. const result = getValue(data[key], target);
  33. if (result) {
  34. return result;
  35. }
  36. }
  37. }
  38. };
  39. const test = {
  40. sname: 'lzx',
  41. data: [
  42. {
  43. demo: "13"
  44. }, {
  45. demo: "123"
  46. },
  47. {
  48. demo: "1234",
  49. name: 'fsdfsss'
  50. }
  51. ],
  52. hello: {
  53. df: "fff"
  54. }
  55. }
  56. console.log(getValue(test, 'hello'));

JS去除字符串中的中括号或是中括号及其中间内容

  1. var str = '这是一个字符串[html]语句;[html]字符串很常见' ;
  2. alert(str.replace(/\[|]/g, '' )); //移除字符串中的所有[]括号(不包括其内容)
  3. //输出:这是一个字符串html语句;html字符串很常见
  4. alert(str.replace(/\[.*?\]/g, '' )); //移除字符串中的所有[]括号(包括其内容)
  5. //输出:这是一个字符串语句;字符串很常见

文件批量下载

  1. a标签 & location.href

a标签及href指向的如果是一个下载链接,那么相当于下载文件,对于单文件下载还是ok的,不过快速点击几个下载按钮,有的下载会被Cancelled。
H5 新特性,HTML 5 里面为 标签添加了一个 download 的属性,我们可以轻易的利用它来实现下载功能。download 的属性值是可选的,它用来指定下载文件的文件名。
<a href="http://somehost/somefile.zip" download="filename.zip">Download file</a>

  1. let files = ['url1', 'url2'] // 所有文件
  2. files.forEach(url => {
  3. if (this.isIE()) { // IE
  4. window.open(url, '_blank')
  5. } else {
  6. let a = document.createElement('a') // 创建a标签
  7. let e = document.createEvent('MouseEvents') // 创建鼠标事件对象
  8. e.initEvent('click', false, false) // 初始化事件对象
  9. a.href = url // 设置下载地址
  10. a.download = '' // 设置下载文件名
  11. a.dispatchEvent(e)
  12. }
  13. })
  1. window.open

window.open可以打开一个新窗口下载文件,不过会快速打开一个新窗口并且关闭,体验非常不好。

  1. iframe
    1. export const downloadFile = (url) => {
    2. const iframe = document.createElement("iframe");
    3. iframe.style.display = "none"; // 防止影响页面
    4. iframe.style.height = 0; // 防止影响页面
    5. iframe.src = url;
    6. document.body.appendChild(iframe); // 这一行必须,iframe挂在到dom树上才会发请求
    7. // 5分钟之后删除(onload方法对于下载链接不起作用,就先抠脚一下吧)
    8. setTimeout(()=>{
    9. iframe.remove();
    10. }, 5 * 60 * 1000);
    11. }

    中划线转驼峰

    ```javascript //-中划线转驼峰 const toHump=(key)=>{ return key.replace(/-(\w)/g,(all,letter)=>{ return letter.toUpperCase(); }) }

// 驼峰转换下划线 const toLine=(key)=> { return key.replace(/([A-Z])/g,”-$1”).toLowerCase(); }

  1. <a name="JBuLh"></a>
  2. # 复制单行内容到粘贴板
  3. ```javascript
  4. /**
  5. * 复制单行内容到粘贴板
  6. * content : 需要复制的内容
  7. */
  8. function copyToClip(content) {
  9. var aux = document.createElement("input");
  10. aux.setAttribute("value", content);
  11. document.body.appendChild(aux);
  12. aux.select();
  13. document.execCommand("copy");
  14. document.body.removeChild(aux);
  15. if (content) {
  16. message.success('复制成功!');
  17. }
  18. }

保留任意小数位数

  1. function round(number, precision) {
  2. return Math.round(+number + 'e' + precision) / Math.pow(10, precision);
  3. //same as:
  4. //return Number(Math.round(+number + 'e' + precision) + 'e-' + precision);
  5. }