JavaScript函数式编程(3)

JavaScript函数式编程(1)内置方法灵活使用
JavaScript函数式编程(2)
前面两篇文章有提到几个原则

  • 尽量不要定义变量,就算定义也最好使用const且保证定义变量后不再更改
  • 尽量使用官方自带的API

很多面试者或ES5重度使用者 长期使用for 循环,但是你在阅读一些优质框架源码时会发现基本会被map filter reduce forEach代替,尽管很多人证明for循环或者多次定义变量对性能并没什么影响,反而函数式编程会牺牲一点性能,并以此为理由排斥函数式编程。

针对以上疑惑,我给自己的解释:

1、js性能很重要,但是没你想的那么重要
现代js 运行环境,无论是手机还是PC,js的性能针对页面微不足道,js是单线程,再看看各位电脑和手机的硬件配置。js所谓影响的一丢丢性能真的是微乎其微。反而是多图或者多http请求导致页面问题。或者你可以试试1000*1000的双for循环 浏览器多长时间跑完。(并不是要建议你可以写双循环)
2、代码少bug,维护性高才是第一追求
当前还是有很多人说微不足道的js性能(其实就是懒得提升自己代码质量)。函数式编程,可以很清晰的跟踪维护核心数据的每一步变动。只要是团队稍微有一些函数式编程的经验加上提交测试前端代码review,维护同事的代码成本一下子降下来。笔者所在的团队,线上bug几乎不会有前端逻辑上或者数据上的问题,只会有一些兼容、逻辑遗漏之类的bug。整体low的bug减少明显,代码维护性高。

以下给出一些案例(前几题太简单可以选择忽略)进行比较:

案例1.最长特殊序列 Ⅰ


下面答案是官方给的答案

var findLUSlength = function(a, b) {
	if(a === b) return -1;
	return a.length > b.length ? a.length : b.length;
};

一般不建议上面这么写,至少要把a、b的 length存起来 ,因为javaScript中的length是通过计算得出的,每次直接调用都会计算一次。


但其实利用API,可以让代码更通俗易懂,如下:

var findLUSlength = function(a, b) {
    if (a === b) {
        return -1
    }
    return Math.max(a.length, b.length)
};

案例2、最后一个单词的长度


以下是官方给出的答案,最明显几个问题

  • 1、变量定义太多
  • 2、有直接使用循环
  • 3、维护难(变量多,代码长)
/**
 * @param {string} s
 * @return {number}
 */
var lengthOfLastWord = function(s) {
    let end = s.length - 1;
    while(end >= 0 && s[end] == ' ') end--;
    if(end < 0) return 0;
    let start = end;
    while(start >= 0 && s[start] != ' ') start--;
    return end - start;
};

以下利用JS自带的API直接给出答案,如果你稍微熟悉,(身为前端应该保证非常熟悉)可以一眼就看出每个步骤

var lengthOfLastWord = function(s) {
    return s.trim().split(" ").reverse()[0].length
};
// 你可以很简单的看出来
//1、去前后空格
//2、转化成数组
//3、翻转取第一个值
//4、给出长度

以下题目基本原创,请勿转载 题目后就是答案,尝试不看答案你自己写出的答案会是什么样子的


1.源数组的每个元素都是一个简单 object,要求根据源数组生成一个新数组,新数组中每个元素在源数组元素的基础上添加 index 属性,值为元素在源数组中的索引(index)(如果源数组元素有这个属性则覆盖)。要求源数组不能改变。

如:
[
  {a:1},
  {a:2},
  {a:1,b:2}
]
=>
[
  {a:1,index:0},
  {a:2,index:1},
  {a:1,b:2,index:2}
]
// 先自己写再看我下面给出的答案




function f(array){
	return array.map((v,index)=> Object.assign({},v,{index}));
}


2.反转源数组,要求源数组不能改变。

如:[1,2,3,4,5] => [5,4,3,2,1]
// 先自己写再看我下面给出的答案






function f(array){
	return array.reduceRight((t, v) => [...t, v], []);
}


3.源数组的每个元素都是一个简单 object,object 结构:{ id:number, name:string, combineId?:number } combineId 为关联 id(即源数组某一个其他元素的 id,可能没有),要求根据源数组生成一个新数组,在新数组元素 object 中添加 combineName 属性,该属性值为当前元素的 combineId 在数组中通过 combineId==id 查找到的某个元素的 name 值(如找不到则为 undefined)。要求源数组不能改变。

如:
 [
   {id:1,name:'n1'},
   {id:2,name:'n2',combindId:3},
   {id:3,name:'n3',combindId:1}
 ]
 =>
 [
   {id:1,name:'n1',combineName:undefined},
   {id:2,name:'n2',combindId:3, combineName:'n3'},
   {id:3,name:'n3',combindId:1, combineName:'n1'}
 ]
// 先自己写再看我下面给出的答案








 function f(array){
   const nameObj = Object.fromEntries(array.map(({id, name}) => [id, name]));
	 return array.map((v)=>Object.assign({},v,{combineName:nameObj[v.combineId]}));
 }


4.源数组的每个元素都是一个简单 object,object 结构:{ id:number, name:string },id 不可能重复,要求以 id 为 key(键),name 为 value(值)生成一个 object。

如:
[
 {id:1,name:'n1'},
 {id:2,name:'n2'},
 {id:3,name:'n3'}
]
=>
{
 '1':'n1',
 '2':'n2',
 '3':'n3'
}
// 先自己写再看我下面给出的答案






function f(array){
	return Object.fromEntries(array.map(({id, name}) => [id, name]));
}


5.源对象 object,由 number 类型的数据做 key,结构为 { name:string, type:string } 的对象做 value,要求写一个方法返回一个新 object,该 object 可以直接使用 number 数字查找到 value 的 name 属性值。源对象 object 不允许修改。

如:
{
 '1':{name:'n1', type:'t1'},
 '2':{name:'n2', type:'t2'},
 '3':{name:'n3', type:'t3'}
}
=>
newObject

console.log(newObject[2]); //n2
console.log(newObject[1]); //n1
// 先自己写再看我下面给出的答案







function f(object){
	return Object.fromEntries(Object.entries(object).map(([key, value]) => [key, value.name]));
}
// 也可以使用proxy代理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值