精通 JavaScript 数据处理大全:手写代码从入门到精通

​🌈个人主页:前端青山
🔥系列专栏:JavaScript篇
🔖人终将被年少不可得之物困其一生

依旧青山,本期给大家带来JavaScript篇专栏内容:JavaScript- 数据处理

目录

1. 实现日期格式化函数

2. 交换a,b的值,不能用临时变量

3. 实现数组的乱序输出

4. 实现数组元素求和

5. 实现数组的扁平化

6. 实现数组去重

7. 实现数组的flat方法

8. 实现数组的push方法

9. 实现数组的filter方法

10. 实现数组的map方法

11. 实现字符串的repeat方法

12. 实现字符串翻转

13. 将数字每千分位用逗号隔开

14. 实现非负大整数相加

13. 实现 add(1)(2)(3)

14. 实现类数组转化为数组

15. 使用 reduce 求和

16. 将js对象转化为树形结构

17. 使用ES5和ES6求函数参数的和

18. 解析 URL Params 为对象

1. 实现日期格式化函数

输入:

dateFormat(new Date('2020-12-01'), 'yyyy/MM/dd') // 2020/12/01
dateFormat(new Date('2020-04-01'), 'yyyy/MM/dd') // 2020/04/01
dateFormat(new Date('2020-04-01'), 'yyyy年MM月dd日') // 2020年04月01日
复制代码
const dateFormat = (dateInput, format)=>{var day = dateInput.getDate() var month = dateInput.getMonth() + 1  var year = dateInput.getFullYear()   format = format.replace(/yyyy/, year)format = format.replace(/MM/,month)format = format.replace(/dd/,day)return format
}
复制代码

2. 交换a,b的值,不能用临时变量

巧妙的利用两个数的和、差:

a = a + b
b = a - b
a = a - b
复制代码

3. 实现数组的乱序输出

主要的实现思路就是:

  • 取出数组的第一个元素,随机产生一个索引值,将该第一个元素和这个索引对应的元素进行交换。

  • 第二次取出数据数组第二个元素,随机产生一个除了索引为1的之外的索引值,并将第二个元素与该索引值对应的元素进行交换

  • 按照上面的规律执行,直到遍历完成

a = a + b
b = a - b
a = a - b
复制代码

还有一方法就是倒序遍历:

var arr = [1,2,3,4,5,6,7,8,9,10];
let length = arr.length,randomIndex,temp;while (length) {randomIndex = Math.floor(Math.random() * length--);temp = arr[length];arr[length] = arr[randomIndex];arr[randomIndex] = temp;}
console.log(arr)
复制代码

4. 实现数组元素求和

  • arr=[1,2,3,4,5,6,7,8,9,10],求和

let arr=[1,2,3,4,5,6,7,8,9,10]
let sum = arr.reduce( (total,i) => total += i,0);
console.log(sum);
复制代码
  • arr=[1,2,3,[[4,5],6],7,8,9],求和

var = arr=[1,2,3,[[4,5],6],7,8,9]
let arr= arr.toString().split(',').reduce( (total,i) => total += Number(i),0);
console.log(arr);
复制代码

递归实现:

let arr = [1, 2, 3, 4, 5, 6] 
​
function add(arr) {if (arr.length == 1) return arr[0] return arr[0] + add(arr.slice(1)) 
}
console.log(add(arr)) // 21
复制代码

5. 实现数组的扁平化

(1)递归实现

普通的递归思路很容易理解,就是通过循环递归的方式,一项一项地去遍历,如果每一项还是一个数组,那么就继续往下遍历,利用递归程序的方法,来实现数组的每一项的连接:

let arr = [1, [2, [3, 4, 5]]];
function flatten(arr) {let result = [];
​for(let i = 0; i < arr.length; i++) {if(Array.isArray(arr[i])) {result = result.concat(flatten(arr[i]));} else {result.push(arr[i]);}}return result;
}
flatten(arr);  //  [1, 2, 3, 4,5]
复制代码

(2)reduce 函数迭代

从上面普通的递归函数中可以看出,其实就是对数组的每一项进行处理,那么其实也可以用reduce 来实现数组的拼接,从而简化第一种方法的代码,改造后的代码如下所示:

let arr = [1, [2, [3, 4]]];
function flatten(arr) {return arr.reduce(function(prev, next){return prev.concat(Array.isArray(next) ? flatten(next) : next)}, [])
}
console.log(flatten(arr));//  [1, 2, 3, 4,5]
复制代码

(3)扩展运算符实现

这个方法的实现,采用了扩展运算符和 some 的方法,两者共同使用,达到数组扁平化的目的:

let arr = [1, [2, [3, 4]]];
function flatten(arr) {while (arr.some(item => Array.isArray(item))) {arr = [].concat(...arr);}return arr;
}
console.log(flatten(arr)); //  [1, 2, 3, 4,5]
复制代码

(4)split 和 toString

可以通过 split 和 toString 两个方法来共同实现数组扁平化,由于数组会默认带一个 toString 的方法,所以可以把数组直接转换成逗号分隔的字符串,然后再用 split 方法把字符串重新转换为数组,如下面的代码所示:

let arr = [1, [2, [3, 4]]];
function flatten(arr) {return arr.toString().split(',');
}
console.log(flatten(arr)); //  [1, 2, 3, 4,5]
复制代码

通过这两个方法可以将多维数组直接转换成逗号连接的字符串,然后再重新分隔成数组。

(5)ES6 中的 flat

我们还可以直接调用 ES6 中的 flat 方法来实现数组扁平化。flat 方法的语法:arr.flat([depth])

其中 depth 是 flat 的参数,depth 是可以传递数组的展开深度(默认不填、数值是 1),即展开一层数组。如果层数不确定,参数可以传进 Infinity,代表不论多少层都要展开:

let arr = [1, [2, [3, 4]]];
function flatten(arr) {return arr.flat(Infinity);
}
console.log(flatten(arr)); //  [1, 2, 3, 4,5]
复制代码

可以看出,一个嵌套了两层的数组,通过将 flat 方法的参数设置为 Infinity,达到了我们预期的效果。其实同样也可以设置成 2,也能实现这样的效果。在编程过程中,如果数组的嵌套层数不确定,最好直接使用 Infinity,可以达到扁平化。 (6)正则和 JSON 方法 在第4种方法中已经使用 toString 方法,其中仍然采用了将 JSON.stringify 的方法先转换为字符串,然后通过正则表达式过滤掉字符串中的数组的方括号,最后再利用 JSON.parse 把它转换成数组:

let arr = [1, [2, [3, [4, 5]]], 6];
function flatten(arr) {let str = JSON.stringify(arr);str = str.replace(/(\[|\])/g, '');str = '[' + str + ']';return JSON.parse(str); 
}
console.log(flatten(arr)); //  [1, 2, 3, 4,5]
复制代码

6. 实现数组去重

给定某无序数组,要求去除数组中的重复数字并且返回新的无重复数组。

ES6方法(使用数据结构集合):

const array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8];
​
Array.from(new Set(array)); // [1, 2, 3, 5, 9, 8]
复制代码

ES5方法:使用map存储不重复的数字

const array = [1, 2, 3, 5, 1, 5, 9, 1, 2, 8];
​
uniqueArray(array); // [1, 2, 3, 5, 9, 8]
​
function uniqueArray(array) {let map = {};let res = [];for(var i = 0; i < array.length; i++) {if(!map.hasOwnProperty([array[i]])) {map[array[i]] = 1;res.push(array[i]);}}return res;
}
复制代码

7. 实现数组的flat方法

function _flat(arr, depth) {if(!Array.isArray(arr) || depth <= 0) {return arr;}return arr.reduce((prev, cur) => {if (Array.isArray(cur)) {return prev.concat(_flat(cur, depth - 1))} else {return prev.concat(cur);}}, []);
}
复制代码

8. 实现数组的push方法

let arr = [];
Array.prototype.push = function() {for( let i = 0 ; i < arguments.length ; i++){this[this.length] = arguments[i] ;}return this.length;
}
复制代码

9. 实现数组的filter方法

Array.prototype._filter = function(fn) {if (typeof fn !== "function") {throw Error('参数必须是一个函数');}const res = [];for (let i = 0, len = this.length; i < len; i++) {fn(this[i]) && res.push(this[i]);}return res;
}
复制代码

10. 实现数组的map方法

Array.prototype._map = function(fn) {if (typeof fn !== "function") {throw Error('参数必须是一个函数');}const res = [];for (let i = 0, len = this.length; i < len; i++) {res.push(fn(this[i]));}return res;
}
复制代码

11. 实现字符串的repeat方法

输入字符串s,以及其重复的次数,输出重复的结果,例如输入abc,2,输出abcabc。

function repeat(s, n) {return (new Array(n + 1)).join(s);
}
复制代码

递归:

function repeat(s, n) {return (n > 0) ? s.concat(repeat(s, --n)) : "";
}
复制代码

12. 实现字符串翻转

在字符串的原型链上添加一个方法,实现字符串翻转:

String.prototype._reverse = function(a){return a.split("").reverse().join("");
}
var obj = new String();
var res = obj._reverse ('hello');
console.log(res);    // olleh
复制代码

需要注意的是,必须通过实例化对象之后再去调用定义的方法,不然找不到该方法。

13. 将数字每千分位用逗号隔开

数字有小数版本:

let format = n => {let num = n.toString() // 转成字符串let decimals = ''// 判断是否有小数num.indexOf('.') > -1 ? decimals = num.split('.')[1] : decimalslet len = num.lengthif (len <= 3) {return num} else {let temp = ''let remainder = len % 3decimals ? temp = '.' + decimals : tempif (remainder > 0) { // 不是3的整数倍return num.slice(0, remainder) + ',' + num.slice(remainder, len).match(/\d{3}/g).join(',') + temp} else { // 是3的整数倍return num.slice(0, len).match(/\d{3}/g).join(',') + temp }}
}
format(12323.33)  // '12,323.33'
复制代码

数字无小数版本:

let format = n => {let num = n.toString() let len = num.lengthif (len <= 3) {return num} else {let remainder = len % 3if (remainder > 0) { // 不是3的整数倍return num.slice(0, remainder) + ',' + num.slice(remainder, len).match(/\d{3}/g).join(',') } else { // 是3的整数倍return num.slice(0, len).match(/\d{3}/g).join(',') }}
}
format(1232323)  // '1,232,323'
复制代码

14. 实现非负大整数相加

JavaScript对数值有范围的限制,限制如下:

Number.MAX_VALUE // 1.7976931348623157e+308
Number.MAX_SAFE_INTEGER // 9007199254740991
Number.MIN_VALUE // 5e-324
Number.MIN_SAFE_INTEGER // -9007199254740991
复制代码

如果想要对一个超大的整数(> Number.MAX_SAFE_INTEGER)进行加法运算,但是又想输出一般形式,那么使用 + 是无法达到的,一旦数字超过 Number.MAX_SAFE_INTEGER 数字会被立即转换为科学计数法,并且数字精度相比以前将会有误差。

实现一个算法进行大数的相加:

function sumBigNumber(a, b) {let res = '';let temp = 0;a = a.split('');b = b.split('');while (a.length || b.length || temp) {temp += ~~a.pop() + ~~b.pop();res = (temp % 10) + res;temp  = temp > 9}return res.replace(/^0+/, '');
}
复制代码

其主要的思路如下:

  • 首先用字符串的方式来保存大数,这样数字在数学表示上就不会发生变化

  • 初始化res,temp来保存中间的计算结果,并将两个字符串转化为数组,以便进行每一位的加法运算

  • 将两个数组的对应的位进行相加,两个数相加的结果可能大于10,所以可能要仅为,对10进行取余操作,将结果保存在当前位

  • 判断当前位是否大于9,也就是是否会进位,若是则将temp赋值为true,因为在加法运算中,true会自动隐式转化为1,以便于下一次相加

  • 重复上述操作,直至计算结束

13. 实现 add(1)(2)(3)

函数柯里化概念: 柯里化(Currying)是把接受多个参数的函数转变为接受一个单一参数的函数,并且返回接受余下的参数且返回结果的新函数的技术。

1)粗暴版

function add (a) {
return function (b) {return function (c) {return a + b + c;}
}
}
console.log(add(1)(2)(3)); // 6
复制代码

2)柯里化解决方案

  • 参数长度固定

var add = function (m) {var temp = function (n) {return add(m + n);}temp.toString = function () {return m;}return temp;
};
console.log(add(3)(4)(5)); // 12
console.log(add(3)(6)(9)(25)); // 43
复制代码

对于add(3)(4)(5),其执行过程如下:

  1. 先执行add(3),此时m=3,并且返回temp函数;

  2. 执行temp(4),这个函数内执行add(m+n),n是此次传进来的数值4,m值还是上一步中的3,所以add(m+n)=add(3+4)=add(7),此时m=7,并且返回temp函数

  3. 执行temp(5),这个函数内执行add(m+n),n是此次传进来的数值5,m值还是上一步中的7,所以add(m+n)=add(7+5)=add(12),此时m=12,并且返回temp函数

  4. 由于后面没有传入参数,等于返回的temp函数不被执行而是打印,了解JS的朋友都知道对象的toString是修改对象转换字符串的方法,因此代码中temp函数的toString函数return m值,而m值是最后一步执行函数时的值m=12,所以返回值是12。

  • 参数长度不固定

function add (...args) {//求和return args.reduce((a, b) => a + b)
}
function currying (fn) {let args = []return function temp (...newArgs) {if (newArgs.length) {args = [...args,...newArgs]return temp} else {let val = fn.apply(this, args)args = [] //保证再次调用时清空return val}}
}
let addCurry = currying(add)
console.log(addCurry(1)(2)(3)(4, 5)())  //15
console.log(addCurry(1)(2)(3, 4, 5)())  //15
console.log(addCurry(1)(2, 3, 4, 5)())  //15
复制代码

14. 实现类数组转化为数组

类数组转换为数组的方法有这样几种:

  • 通过 call 调用数组的 slice 方法来实现转换

Array.prototype.slice.call(arrayLike);
复制代码
  • 通过 call 调用数组的 splice 方法来实现转换

Array.prototype.splice.call(arrayLike, 0);
复制代码
  • 通过 apply 调用数组的 concat 方法来实现转换

Array.prototype.concat.apply([], arrayLike);
复制代码
  • 通过 Array.from 方法来实现转换

Array.from(arrayLike);
复制代码

15. 使用 reduce 求和

arr = [1,2,3,4,5,6,7,8,9,10],求和

let arr = [1,2,3,4,5,6,7,8,9,10]
arr.reduce((prev, cur) => { return prev + cur }, 0)
复制代码

arr = [1,2,3,[[4,5],6],7,8,9],求和

let arr = [1,2,3,4,5,6,7,8,9,10]
arr.flat(Infinity).reduce((prev, cur) => { return prev + cur }, 0)
复制代码

arr = [{a:1, b:3}, {a:2, b:3, c:4}, {a:3}],求和

let arr = [{a:9, b:3, c:4}, {a:1, b:3}, {a:3}] 
​
arr.reduce((prev, cur) => {return prev + cur["a"];
}, 0)
复制代码

16. 将js对象转化为树形结构

// 转换前:
source = [{id: 1,pid: 0,name: 'body'}, {id: 2,pid: 1,name: 'title'}, {id: 3,pid: 2,name: 'div'}]
// 转换为: 
tree = [{id: 1,pid: 0,name: 'body',children: [{id: 2,pid: 1,name: 'title',children: [{id: 3,pid: 1,name: 'div'}]}}]
复制代码

代码实现:

function jsonToTree(data) {// 初始化结果数组,并判断输入数据的格式let result = []if(!Array.isArray(data)) {return result}// 使用map,将当前对象的id与当前对象对应存储起来let map = {};data.forEach(item => {map[item.id] = item;});// data.forEach(item => {let parent = map[item.pid];if(parent) {(parent.children || (parent.children = [])).push(item);} else {result.push(item);}});return result;
}
复制代码

17. 使用ES5和ES6求函数参数的和

ES5:

function sum() {let sum = 0Array.prototype.forEach.call(arguments, function(item) {sum += item * 1})return sum
}
复制代码

ES6:

function sum(...nums) {let sum = 0nums.forEach(function(item) {sum += item * 1})return sum
}
复制代码

18. 解析 URL Params 为对象

let url = 'http://www.domain.com/?user=anonymous&id=123&id=456&city=%E5%8C%97%E4%BA%AC&enabled';
parseParam(url)
/* 结果
{ user: 'anonymous',id: [ 123, 456 ], // 重复出现的 key 要组装成数组,能被转成数字的就转成数字类型city: '北京', // 中文需解码enabled: true, // 未指定值得 key 约定为 true
}
*/
复制代码
function parseParam(url) {const paramsStr = /.+\?(.+)$/.exec(url)[1]; // 将 ? 后面的字符串取出来const paramsArr = paramsStr.split('&'); // 将字符串以 & 分割后存到数组中let paramsObj = {};// 将 params 存到对象中paramsArr.forEach(param => {if (/=/.test(param)) { // 处理有 value 的参数let [key, val] = param.split('='); // 分割 key 和 valueval = decodeURIComponent(val); // 解码val = /^\d+$/.test(val) ? parseFloat(val) : val; // 判断是否转为数字if (paramsObj.hasOwnProperty(key)) { // 如果对象有 key,则添加一个值paramsObj[key] = [].concat(paramsObj[key], val);} else { // 如果对象没有这个 key,创建 key 并设置值paramsObj[key] = val;}} else { // 处理没有 value 的参数paramsObj[param] = true;}})return paramsObj;
}
复制代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/267629.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用pdf2docx轻松将PDF转换成docx

目录 一、什么是pdf2docx&#xff1f; 二、为什么选择pdf2docx&#xff1f; 三、如何使用pdf2docx&#xff1f; 四、常见问题和解决方案 总结 随着数字化时代的到来&#xff0c;PDF和docx格式已经成为我们日常工作中最常用的文档格式之一。然而&#xff0c;有时我们需要将…

电脑录制高清视频文件是怎么设置的

在当今数字化的时代&#xff0c;电脑已经成为我们生活中不可或缺的工具。除了处理文档、浏览网页等常见功能外&#xff0c;它还可以轻松录制高清视频文件。那么&#xff0c;具体如何设置电脑才可以录制高清视频呢&#xff1f; 首先&#xff0c;要确保电脑的硬件配置是否能够支…

【面试】Java最新面试题资深开发-Java中的并发集合类

问题五&#xff1a;Java中的并发集合类 Java提供了许多并发集合类来处理多线程环境下的数据共享和同步。你能列举一些Java中常用的并发集合类&#xff0c;并简要说明它们的特点和使用场景吗&#xff1f; 以下六个是经常被使用的&#xff0c;它们在实际开发中发挥着重要作用&a…

探究振弦采集仪在工程监测中的应用

探究振弦采集仪在工程监测中的应用 振弦采集仪是一种专门用于测量结构振动的仪器&#xff0c;在工程监测中有着广泛的应用。它通过采集振动信号&#xff0c;分析结构的振动特性&#xff0c;从而评估结构的安全性能&#xff0c;指导工程设计和施工。本文将从振弦采集仪的基本原…

【日志技术】附Logback入门教程

文章目录 日志概论日志的体系Logback快速入门日志配置文件配置日志级别 日志概论 什么是日志&#xff1f;其实可以通过下面几个问题来了解的。 系统系统能记住某些数据被谁操作&#xff0c;比如被谁删除了&#xff1f;想分析用户浏览系统的具体情况&#xff0c;比如挖掘用户的…

香港麦理浩径一二段两天徒步沙滩露营

文章目录 香港麦理浩径一二段两天徒步沙滩露营 香港麦理浩径一二段两天徒步沙滩露营 凌晨六点起床慢跑7.5公里&#xff0c; 回去洗澡&#xff0c;然后给自己煮了早餐吃完出发时已是早上八点半了。 我在地铁上&#xff0c;中途看了群信息&#xff0c;说要准备港币&#xff0c;…

cache教程 5.分布式节点的通信

0.对原教程的一些见解 其回顾完请求流程就是抽象了两个接口&#xff0c;PeerPicker和PeerGetter。这样操作&#xff0c;读者阅读时可能很难快速明白其含义&#xff0c;不好理解为什么就创建出两个接口&#xff0c;感觉会比较疑惑。原教程的评论中也有讨论这点。 本教程就先不创…

『 Linux 』进程地址空间概念

文章目录 &#x1fad9; 前言&#x1fad9; 进程地址空间是什么&#x1fad9; 写时拷贝&#x1fad9; 可执行程序中的虚拟地址&#x1fad9; 物理地址分布方式 &#x1fad9; 前言 在c/C中存在一种内存的概念; 一般来说一个内存的空间分布包括栈区,堆区,代码段等等; 且内存是…

精通C语言函数,轻松入门!通过实例掌握技巧

一、题目&#xff1a; 1~n的倒数相加&#xff0c;即&#xff1a;1 1/2 1/3 …… 1/n 二、上代码&#xff1a; #include <stdio.h> double fun(int n) // 定义一个函数&#xff0c;参数为n&#xff08;形参&#xff09; { double sum 0; // 初始化…

vue3+vite4中使用svg,使用iconfont-svg图标

记录一下vue3中如何使用svg图标&#xff0c;vue2中大家常用iconfont字体图标&#xff0c;现在vue3大家都又推荐svg的方式使用图表&#xff0c;包括elementplus组件库也变成使用svg方式引用图标。 1、创建svg组件 components/IconSvg.vue <template><svg class"…

代理模式:解析对象间的间接访问与控制

目录 引言 理解代理模式 不同类型的代理模式 代理模式的应用场景 代理模式的优缺点 优点 缺点 实际案例&#xff1a;Java中的代理模式应用 结语 引言 代理模式是软件设计模式中的一种结构型模式&#xff0c;旨在为其他对象提供一种代理以控制对这个对象的访问。它允许你…

改造项目用 开口互感器AKH-0.66/KK-∮24 操作方便,节约时间!

1.产品特点 产品外形美观&#xff0c;安装、接线方便&#xff0c;主要用于电力运维及用电改造项目&#xff0c;一般输出为 AC 5A、 1A 或者毫安等信号&#xff0c;具有体积小、精度高、带载能力强、安装方便等优点&#xff0c;为用户改造项 目节省人力、物力、财力&#xff0c…