《JavaScript函数式编程》读后感


Posted in Javascript onAugust 07, 2015

本文章记录本人在学习 函数式 中理解到的一些东西,加深记忆和并且整理记录下来,方便之后的复习。

在近期看到了《JavaScript函数式编程》这本书预售的时候就定了下来。主要目的是个人目前还是不理解什么是函数式编程。在自己学习的过程中一直听到身边的人说面向过程编程和面向对象编程,而函数式就非常少。为了自己不要落后于其他同学的脚步,故想以写笔记的方式去分享和记录自己阅读中所汲取的知识。

js 和函数式编程

书中用了一句简单的话来回答了什么是函数式编程:

函数式编程通过使用函数来将值转换为抽象单元,接着用于构建软件系统。
我觉得一定有同学看了这一句还是不怎么动什么是函数式编程,且为什么要使用函数式编程。后面的很多例子都使用到了Underscore。

以函数为抽象单元

抽象方法是指隐藏了细节的函数。举一个书中的例子,一个检测输出年龄值的函数(主要是关于错误和警告的报告):

function parseAge(age) {
  if (!_.isString(age))
    throw new Error("Expecting a string");
  var a;
  console.log("Attempting to parse an age");

  a = parseInt(age, 10);
  if (_.isNaN(a)) {
    console.log(["Could not parse age: "].join());
    a = 0;
  }

  return a;
}

上面的函数判断我们是不是输入一个年龄,且必须是字符串形式。接着就是来运行这个函数:

parseAge("42"); //=> 42
parseAge(42); //=> Error:Expecting a string
parseAge("hhhh"); //=> 0

上面的parseAge函数工作正常没有什么问题。如果我们要修改输出错误=信息和警告的呈现方式、那么就需要修改相应的代码行,以及其他地方的输出模式。书中给的方法是通过将它们抽象成不同的函数来实现:

function fail(thing) {
  throw new Error(thing);
}

function warn(thing) {
  console.log(["WARNING:", thing].join(''));
}

function note(thing) {
  console.log(["NOTE:", thing].join(''));
}

接着就是使用上面的函数,去重构parseAge这个函数。

funciton parseAge(age) {
  if (!_.isString(age))
    fail("Expecting a string");
  var a;

  note("Attempting to parse an age");
  a = parseInt(age, 10);

  if (_.isNaN(a)) {
    warn(["Could not parse age:", age].join(""));
    a = 0;
  }

  return a;
}

把报告错误的代码都放到不同的函数里去,且重构后的parseAge和之前的也没有多大的变化。但是不同的就是现在报告错误、信息和警告的想法已经被抽象化。错误、信息和警告的报告结果也是完全被修改了。

这么做是,由于行为包含在单一的函数中,所以函数可以被能够提供类似行为的新函数取代,或直接被完全不同的行为取代。

封装和隐蔽

这个标题很容易理解,举个例子。像我们经常使用iife来避免全局的污染,这就是一个封装和隐蔽的很好例子。通过使用iife来隐蔽自己的写的一些变量和方法,目的就是不去污染全局的环境。这也是使用闭包的方式来隐蔽数据。

因为闭包也是一种函数。且和现在在学习函数式编程有莫大的关系。但是也不要忘记了之前学习的面向对象式封装,毕竟这两者不能说谁更加的好。但是都掌握了也不是一件什么坏事。一句老话:看需求。

以函数为行为单位

隐藏数据和行为(通常不方便于快速修改)只是一种讲函数作为抽象单元的方式。另一种方式就是提供一种简单地存储方式和传递基本行为的离线散单元。

书中一个小栗子,通过使用js语法来索引数组中的一个值:

var arr = ['a', 'b', 'c'];
arr[1] //=> b

虽然上面索引数组中的中的一个值很简单,但并没有办法可以在不把它放到函数里的前提下,获取这个行为并根据需要来使用他/她。写一个简单函数nth,用来索引数组中的一个值:

function nth(a, index) {
  return a[index];
}

接着运行:

nth(arr, 1); //=> b
运行成功,但是如果传入一个空对象时,就会报错了。因此,如果想围绕nth来实现函数抽象,我们或许会设计下面的声明:nth返回一个存储在允许索引访问的数据类型中的有效袁术。这段声明的关键在于索引数据的类型的概念。或许需要一个函数来判断类型:

function isIndexed(data) {
  return _.isArray(data) || _.isString(data);
}

接着继续完善nth函数。isIndexed函数是一个提供了判断某个数据是否为字符串或者数组的抽象。

function nth(a, index) {
  if (!_.isNumber(index)) 
    fail("Expected a number as the index");
  if (!isIndexed(a))
    fail("Not supported on non-indexed type");
  if ((index < 0) || (index > a.length - 1))
    fail("Index value is out of bounds");

  return a[index];
}

从index抽对象构建nth函数抽象的方式一样,也可以以同样的方式来构建一个second抽象:

function second(a) {
  return nth(a, 1);
}

函数second允许在一个不同但相关的情况下,正确的使用nth函数:

second(arr); //=> b
通过上面的栗子,就知道。我们可以把每一步都抽象成一个函数,把每一个参数都抽象出来。虽然这样写感觉定义了许多函数。不过这样更加容易理解每一项的功能和流程。

数据抽象

JavaScript 的对象原型模型是一个丰富且基础的数据方案。
因为js没有类的原因,就有了许多模拟类的方法,且在ES6上也出现了class关键字。尽管类有许多长处,但很多的时候js应用程序的数据需求币类中的简单的要多。

基于类的对象系统的一个有理的论据是实现用户界面的历史使用。
js中的对象和数组已经能够满足我们对数据的操作了,且Underscore也是重点也是如何处理数组和对象。

实施和使用的简易性是使用js的核心数据结构进行数据建模的目的。这并不是说面向对象或者基于类的方法就完全没有用。处理集合为中心的函数式方式更加适合处理与人有关的数据,而面向对象的方法最适合模拟人。

js函数式初试

在开始函数式编程前,需要先定义两个常用且有用的函数:

function existy(x) {
  return x != null
}

function truthy(x) {
  return (x !== false) && existy(x);
}

existy函数旨在定义事物之前的存在。js中就有两个值可以表示不存在:null和undefined。
truthy函数用来判断一个对象是否应该认为是true的同义词。

我们可以在很多地方使用到这两个函数,其实函数式理念来自于它们的使用。有些同学可能已经熟悉了许多js实现中的map forEach等方法。且Underscroe也提供了许多类似的方法,这也许就是选择Underscroe来辅助学习函数式编程的原因。

简单说下就是:

一个对”存在“的抽象函数的定义。
一个建立在存在函数之上的,对”真“的抽象函数定义。
通过其他函数来使用上面的两个函数,以实现更多的行为。

加速

大概了解了函数式编程之后。你可能会想这函数式编程不是很慢吗?比如前面获取数组索引,有必要定义一个函数来专门获取吗?直接用arr[index]绝对比那些函数来的快。

var arr = [1, 2, 3, 4, 5];

// 最快
for (var i = 0; i < arr.length; i++) {
  console.log(arr[i]);
}

// 较慢
_.each(arr, function (val, index) {
  console.log(index);
});

但是我们在写代码的时候可能不会考虑的那么深,也许使用函数的确比原生要慢一些。但是大多数情况下也不会去在乎那么点时间,且现在有强大的v8引擎,大部分情况下的他都能很高效的编译和执行我们的js代码。所以我们没有必要在还没有写出正确的代码前考虑运算速度。

如果是我来选择的话,可能会更加关注与代码的风格。那种写法写的舒服看的舒服就使用哪一种,当然也是要保证基本的运算速度下,以不至于慢的离谱。看的舒服的代码比跑的快的代码可能更加有成就感。

总结

看完了第一章也是可以小结一下js的函数式编程。下面引用书上的总结:

确定抽象,并为其构建函数。
利用已有的函数来构建更加复杂的抽象。
通过将现有的函数传给其他的函数来构建更加复杂的抽象。
单是构建抽象还是不够的,如果能够把强大的数据抽象结合来实现函数式编程效果会更加好。

后面的章节读后感会慢慢的分享给大家,敬请关注。

Javascript 相关文章推荐
用js实现上传图片前的预览(TX的面试题)
Aug 14 Javascript
CutePsWheel javascript libary 控制输入文本框为可使用滚轮控制的js库
Feb 07 Javascript
关于用Jquery的height()、width()计算动态插入的IMG标签的宽高的问题
Dec 08 Javascript
artDialog双击会关闭对话框的修改过程分享
Aug 05 Javascript
使用jQuery5分钟快速搞定双色表格的简单实例
Aug 08 Javascript
Javascript之面向对象--封装
Dec 02 Javascript
tablesorter.js表格排序使用方法(支持中文排序)
Feb 10 Javascript
SpringBoot+Vue前后端分离,使用SpringSecurity完美处理权限问题的解决方法
Jan 09 Javascript
JS弹窗 JS弹出DIV并使整个页面背景变暗功能的实现代码
Apr 21 Javascript
Angular5中提取公共组件之radio list的实例代码
Jul 10 Javascript
微信小程序入口场景的问题集合与相关解决方法
Jun 26 Javascript
微信小程序中如何计算距离某个节日还有多少天
Jul 15 Javascript
jQuery过滤HTML标签并高亮显示关键字的方法
Aug 07 #Javascript
jquery实现先淡出再折叠收起的动画效果
Aug 07 #Javascript
C++中的string类的用法小结
Aug 07 #Javascript
Grunt入门教程(自动任务运行器)
Aug 06 #Javascript
PhantomJS快速入门教程(服务器端的 JavaScript API 的 WebKit)
Aug 06 #Javascript
jQuery实现hover合成事件的方法
Aug 06 #Javascript
Ajax清除浏览器js、css、图片缓存的方法
Aug 06 #Javascript
You might like
NT IIS下用ODBC连接数据库
2006/10/09 PHP
Codeigniter检测表单post数据的方法
2015/03/21 PHP
Ubuntu彻底删除PHP7.0的方法
2018/07/27 PHP
利用JQuery+EasyDrag 实现弹出可拖动的Div,同时向Div传值,然后返回Div选中的值
2009/10/24 Javascript
JS计算网页停留时间代码
2014/04/28 Javascript
jquery的ajax跨域请求原理和示例
2014/05/08 Javascript
JS实现当前页居中分页效果的方法
2015/06/18 Javascript
浅析webpack 如何优雅的使用tree-shaking(摇树优化)
2017/08/16 Javascript
javascript实现文字无缝滚动效果
2017/08/26 Javascript
微信小程序实现预览图片功能
2020/10/22 Javascript
koa大型web项目中使用路由装饰器的方法示例
2019/04/02 Javascript
gulp构建小程序的方法步骤
2019/05/31 Javascript
javascript设计模式 ? 策略模式原理与用法实例分析
2020/04/21 Javascript
Vue中keep-alive组件的深入理解
2020/08/23 Javascript
使用scrapy实现爬网站例子和实现网络爬虫(蜘蛛)的步骤
2014/01/23 Python
python抓取网页图片并放到指定文件夹
2014/04/24 Python
tensorflow识别自己手写数字
2018/03/14 Python
Django配置celery(非djcelery)执行异步任务和定时任务
2018/07/16 Python
使用 Django Highcharts 实现数据可视化过程解析
2019/07/31 Python
关于numpy中eye和identity的区别详解
2019/11/29 Python
使用python客户端访问impala的操作方式
2020/03/28 Python
Python小白垃圾回收机制入门
2020/06/09 Python
python 爬取百度文库并下载(免费文章限定)
2020/12/04 Python
Pycharm制作搞怪弹窗的实现代码
2021/02/19 Python
美国电力供应商店/电气批发商:USESI
2018/10/12 全球购物
含精油的天然有机化妆品:Indemne
2019/08/27 全球购物
简历自荐信
2013/12/02 职场文书
行政办公室岗位职责
2014/03/18 职场文书
检举信的格式及范文
2014/04/04 职场文书
综治维稳工作汇报
2014/10/27 职场文书
朋友聚会开场白
2015/06/01 职场文书
2016年优秀团员事迹材料
2016/02/25 职场文书
广告策划的实习心得体会总结!
2019/07/22 职场文书
面试分析分布式架构Redis热点key大Value解决方案
2022/03/13 Redis
Redis高可用集群redis-cluster详解
2022/03/20 Redis
SQL Server中搜索特定的对象
2022/05/25 SQL Server