博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
前端进击的巨人(四):略知函数式编程
阅读量:6432 次
发布时间:2019-06-23

本文共 4400 字,大约阅读时间需要 14 分钟。

系列更文前三篇文章,围绕了一个重要的知识点:"函数"

函数调用栈、函数执行上下文、函数作用域到闭包。可见不理解函数式编程,代码都撸不好。

前端进击的巨人(四):略知函数式编程

 函数是一等公民

函数与其它数据类型一样,可以作为值赋给变量,作为参数传递或返回值返回,也可以像对象一样给函数创建属性(不推荐给函数加属性,虽然可用)。

函数在实际开发中应用:

  1. 函数声明
  2. 函数表达式
  3. 匿名函数
  4. 自执行函数
// 函数声明function getName() {    //...    }// 函数表达式var getName = function() {    //...}// 匿名函数setTimeout(function(){    //...}, 1000);// 自执行函数(function(){    //...})();

何为一等:优先级

函数声明在"执行上下文创建阶段"就会进行声明并赋值,而var声明变量会初始化为undefined,实际赋值会等到"执行上下文执行阶段"。函数表达式使用var来声明,因此它遵循的是变量声明的规则。( 如果函数名与变量重名,函数优先赋值)

"函数声明优先级高于变量声明和函数表达式,自称一等公民。"

// 代码书写:console.log(getName);getName();var getName;getName = '我的名字';function getName(){    //...}console.log(getName);// 实际执行var getName;            // 变量名与函数名重名,函数优先赋值function getName() {    //...}console.log(getName);getName();getName = '我的名字';console.log(getName);

函数式编程

函数式编程是一种编程思维方式,它建议我们在程序编写时,对复用性高的功能代码进行函数封装,实现代码的高复用性。

新手朋友往往是一块代码多次出现在不同的地方,常见的例子就是ajax请求方法运用,在需要请求后端数据时多次出现一串ajax请求代码。

如果想要对ajax请求统一做异常处理,或管理后端返回状态码,是不是每处代码都要修改???但是如果把ajax请求代码封装成一个函数,接口url和数据data通过参数传递到函数内部处理,后期扩展维护都方便修改,复用性扩展性都更加优秀。

所以实际敲代码过程中,要经常提醒自己运用函数式编程的思维方式,只要有可能出现多次的业务逻辑代码,那么就要考虑是否封装成函数,以便后续统一调用。

function sumScore(list) {    var totalScore = 0    for (var i = 0; i < list.length; i++) {        totalScore += list[i];            }    return totalScore;    }var list = [10, 8, 9, 7];var totalScore = sumScore(list);    // 计算总分

TIPS: 函数名建议使用动词,如addUser(),sumScore(),getUser()...

纯函数

纯函数:相同的输入对应相同的输出,稳定没有副作用(不改变外部变量的值)

相同的输入,相同的输出

相同的参数传入调用,要有相同的结果输出,概念有点绕,上代码栗子:

function getDate() {    return new Date();}var dateOne = getDate();var dateTwo = getDate();var dateThr = getDate();

上述代码中调用了三次getDate(),三次返回的值都不一样。相同的输入并没有相同的输出,所以getDate()并不是一个纯函数。

TIPS:函数中使用new Date(),Math.random(), 异步等都可能造成函数不稳定。

没有副作用(不改变外部环境的值)

部分小伙伴的代码,在函数里面直接修改参数的值,这是一种非常不推荐的做法,这样做会造成代码环境不可控制,污染外部变量环境,一旦出现错误排查起来:心累,三个字心好累。

函数有自己的局部作用域,因此函数中,对需要使用到的变量,管控在自身的作用域下。如果需要修改外部参数的值,通过函数返回值返回给函数调用者。修改外部参数值的操作不在函数内进行,确保对外部环境没有副作用。

TIPS:参数为引用类型时,参数复制的是地址指针,避免修改了引用类型中属性值污染外部环境,如需使用建议手动深拷贝赋值。

function getGirlGift(list) {    // 避免污染参数为引用类型的list,对list深拷贝    var newList = JSON.parse(JSON.stringify(list));    newList.map(girl => {        girl.gift = girl.age > 18 ? 'lipstick' : 'chocolates';    });    return newList;    // 返回新值}var girlList = [    {name: 'Kelly', age: 20},    {name: 'Alic', age: 16},    {name: 'Moon', age: 23},    {name: 'Nana', age: 17}];var girlGiftList = getGirlGift(girlList);girlList         // 原用girlList不变girlGiftList     // 每个girl多了gift属性

Array对象的函数(纯与不纯)

// 不纯的函数array.push();       // 数组尾部插入array.pop();        // 删除并返回数组最后一个元素array.unshift();    // 数组头部插入array.shift();      // 删除并返回数组第一元素array.splice();     // 删除元素,并向数组添加元素array.reverse();    // 颠倒数组元素的顺序array.sort();       // 排序数组元素// 纯函数array.slice();      // 数组中返回选定的元素array.concat();     // 连接数组,并发挥新数组array.join();       // 按分隔符连接数组,返回字符串

纯函数的应用:状态管理Redux,Vuex

流行框架中状态管理就是纯函数的实践应用,引用redux的应用,reducer中返回新的状态数据state,但不能去直接去修改state数据,以下为redux中reducer的例子代码:

export default (state = defaultState, action) => {    let newState = JSON.parse(JSON.stringify(state));    switch (action.type) {        case DELETE_TODO_ITEM:            newState.list.splice(action.value, 1);        break;        case ADD_TODO_ITEM:            if (newState.inputValue.trim().length) {                newState.list.push(newState.inputValue);            }            newState.inputValue = '';        break;        case INIT_LIST_ACTION:             newState = action.data        break;        default:         break;    }    return newState;}

"自执行函数 + 闭包" 实现模块化

模块化包括:

  1. 私有变量
  2. 私有方法
  3. 公有变量
  4. 公有方法

上篇中我们讲解了作用域、闭包的原理机制。

"自执行函数可实现块级作用域,而闭包则可实现外部环境对函数作用域内部数据的访问。"

// 自执行函数 + 闭包实现模块化(function MakeModule(window) {    var name = '以乐之名';    var age = 28;    var job = '程序员';        function changeJob(newJob) {        job = newJob;    }        function getName() {        return name;            }       window.modulePublic = {        changeJob: changeJob,        getName: getName    }})(window);window.modulePublic.getName();window.modulePublic.changeJob('产品经理');

对作用域,以及闭包知识还没掌握的小伙伴,可回阅。

高阶函数

高阶函数是一个函数,它接收函数作为参数或将函数作为输出返回

JavaScript中常用的高阶函数:

  1. Array.prototype.map (映射遍历)
  2. Array.prototype.filter (过滤)
  3. Array.prototype.reducer(累计)

除了内置的高阶函数,我们实际开发中,高阶函数应用的最多就是回调函数了。

function getOrder(url, datas, callBack) {    return $.post(url, datas, callBack(orderInfo));}// getOrder就是一个高阶函数,接收callBack函数作为参数

高阶函数的概念很简单,"本身是函数,参数是函数,或返回值是函数"


参考文档:

系列更文请关注专栏:,不断更新中。。。

本文首发Github,期待Star!

作者:以乐之名
本文原创,有不当的地方欢迎指出。转载请指明出处。
你可能感兴趣的文章
我的Git忽略文件
查看>>
洛谷2219:[HAOI2007]修筑绿化带——题解
查看>>
监控webservice信息
查看>>
a标签中href=""的几种用法(转)
查看>>
python
查看>>
ubuntu 常用生产环境部署配置测试调优
查看>>
【JS】//将中文逗号转换为英文逗号
查看>>
在VS2012中实现Ext JS的智能提示太简单了
查看>>
Extnet Direct 提交后台事件文件下载设置
查看>>
邻接矩阵与二叉排序树
查看>>
CSS选择器
查看>>
购物车练习
查看>>
js实现在表格中删除和添加一行
查看>>
SOCKET简单爬虫实现代码和使用方法
查看>>
导出excel数字变成科学计数法解决办法
查看>>
跨域解决方案汇总
查看>>
In App Purchase
查看>>
js判断对象的类型的四种方式
查看>>
ETL (数据仓库技术)
查看>>
count(*)与count(1)、count('xxx')等在使用语法方面的区别
查看>>