从一道面试题掌握ES6的综合应用,题目其实很简单,如下图。//有如下数据结构constdata=[{key:'name',value:'豆皮饭'},{key:'age',value:1,},{key:'from',value:'数据平台'}]//实现一个转换函数processFn//根据对应的key和value生成对象//要求尽可能多的使用es6的新特性,尽量少声明变量,减少副作用。constprocessFn=data=>processData{name:'斗皮范儿',age:1,from:'DataPlatform'}很多考生看了题目,有想法赶紧写出来啊。先看实现最多的版本constprocessFn=data=>{constprocessData={};for(leti=0;i,一个是块级声明let,一个是常量声明const。这里可以问一个扩展测试点,如何实现一个真正的const,因为这里的const其实保证的不是变量的值不能改变,而是变量指向的内存地址存储的数据不能改变。如何实现一个真正只读的对象,下面给出答案。constconstantize=(obj)=>{Object.freeze(obj);Object.keys(obj).forEach((key,i)=>{if(typeofobj[key]==='object'){constantize(obj[key]);}});};开始改造ES6,继续上面的问题。其实如果问ES6有什么新特性,很多人可以回答很多,但是一旦应用到真正的代码编写中,你还是会用老套的方式。其实这道题,比如箭头函数、解构赋值、展开运算符、使用表达式作为对象属性名等等,这些ES6的特性都可以用到。让我们一一了解这些功能。代入到这道题中,让我们来体验一下综合使用ES6的感受。首先,先添加解构赋值。解构赋值可以很容易地从一个对象中获取一个值。这里,可以在获取数组中每个对象的key和value时使用。constprocessFn=data=>{constprocessData={};for(leti=0;i{constprocessData={};for(let{key,value}ofdata){processData[key]=value;}returnprocessData;}然后,可以加上展开运算符,对于一个对象,一般来说,展开运算符的作用就是组合一个对象。ES6时代,也可以使用Object.assign。这两种方法实际上都是可行的。但是无论使用哪种方法,都会遇到一个问题。该属性是一个动态变量。在ES5时代,如果要将属性作为变量进行对象赋值,只能使用如下方法:constkeyName='name';constobj={}obj[keyName]='xxxx';但是ES6允许我们使用字面量来完成这个,只需在属性表达式中添加一个[],现在使用扩展运算符和对象属性表达式的组合来优化查看代码。constprocessFn=data=>{constprocessData={};for(let{key,value}ofdata){Object.assign(processData,{[key]:value})}returnprocessData;}或constprocessFn=data=>{letprocessData={};for(let{key,value}ofdata){processData={...processData,[key]:value}}returnprocessData;}这样就成功集成了这些ES6特性现在已经用过了,下面总结一下现阶段用到的ES6特性,const、let、箭头函数、展开运算符、for...of、解构赋值、对象属性表达式。那就是七。减少一些副作用但是这还没完,题目中还有一个要求,尽量少声明变量,以减少副作用。除了函数声明所必需的声明const之外,还有两个显式声明。至少可以将这种显式声明的数量减少到几个。答案其实是0。这时候就需要修改for循环了,因为for循环肯定会有显式的const或者let语句。for循环本身就是一种命令式编程方式。如果您使用声明性方法,它可能会将显式声明变成隐式参数。公式语句可以进一步提高代码的可读性和简洁性,这其实卡住了很多考生。解的思路其实可以转化为如何所谓的foldanarray,就是把数组的多项组合成一项。这其实涉及到一个ES5的数组函数,reduce,众所周知,reduce的经典使用当然是累加的。[1,2,3].reduce((total,item)=>total+item,0)其实用类比的思想,将对应的数替换为数组中的对象,累加为取而代之的是提取键和值。合并,数组的合并是一种变相的堆积。有了reduce,就可以充分发挥ES6的结合力。集成代码constprocessFn=data=>data.reduce((obj,{key,value})=>{return{...obj,[key]:value};},{})最后的return其实可以去掉,这样代码就可以在一行空格内实现,只需要在箭头函数返回对象的时候加一个括号即可。constdata=>data.reduce((obj,{key,value})=>({...obj,[key]:value}),{})至此,我们对这道题的改造就结束了,综合使用ES6特性,减少显式声明。写出这样的代码,回答这道题就可以毕业了。鸡蛋时间结束了吗?还没有。可见,ES6虽然很强大,但还是需要学习各种特性才能掌握,还需要结合ES5的一些特性才能发挥最好的效果。有没有一种和谐统一的形式来做到这一点?事实上,有。稳住,我们得加快速度。进入声明式世界,打开函数式编程之门。说到函数式编程(FunctionalProgram),其实是一个规则。如果你是入门,你只需要记住以下公理和概念。类比小说《三体》中的黑暗森林法则是这样解释的。函数是一等公民(functionfirst)。在FP的世界里,只有函数。函数本身具有可组合的特性(composition),但函数本身是纯的(pure)。如果想继续了解函数式编程,还有两个比较重要的概念Curry(咖喱)和PointFree有一个很重要的JS函数式编程的工具库,没错,它不是lodash而是Ramda,用Ramda来做上面的问题。//打开http://ramda.cn/docs/,在控制台粘贴以下代码constdata=[{key:'name',value:'豆皮饭儿'},{key:'age',value:1,},{key:'from',value:'dataplatform'}]constprocessFn=R.reduce(R.useWith(R.merge,[R.identity,R.converge(R.objOf,[R.prop('key'),R.prop('value')])]),{})console.log(processFn(data))初看代码,粗心,没看懂,就像一个wallfacer一样晦涩难懂,就像系列的口头禅一样,对吧,但在某种程度上,甚至在表面上,它充满了和谐简洁的美感,具有高度的秩序和统一性,并且完全符合上述两个公理和两个重要概念。如果你对什么是函数式编程,它的主要概念是什么,具体的应用场景是什么感兴趣,我会另写一篇文章详细讲一下函数式编程。结束