《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 相关文章推荐
Jquery下:nth-child(an+b)的使用注意
May 28 Javascript
js使用for循环及if语句判断多个一样的name
Sep 09 Javascript
基于jQuery+Cookie实现的防止刷新的在线考试倒计时
Jun 19 Javascript
JavaScript获取当前运行脚本文件所在目录的方法
Feb 03 Javascript
jQuery实现下拉框多选 jquery-multiselect 的实例代码
Jul 14 Javascript
几种二级联动案例(jQuery\Array\Ajax php)
Aug 13 Javascript
微信小程序 数组(增,删,改,查)等操作实例详解
Jan 05 Javascript
使用AngularJS编写多选按钮选中时触发指定方法的指令代码详解
Jul 24 Javascript
js读取本地文件的实例
Dec 22 Javascript
微信小程序实现topBar底部选择栏效果
Jul 20 Javascript
了解JavaScript函数中的默认参数
May 30 Javascript
vue生命周期钩子函数以及触发时机
Apr 26 Vue.js
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
php自动获取目录下的模板的代码
2010/08/08 PHP
php中计算程序运行时间的类代码
2012/11/03 PHP
ThinkPHP字符串函数及常用函数汇总
2014/07/18 PHP
PHP实现RSA签名生成订单功能【支付宝示例】
2017/06/06 PHP
关于laravel 日志写入失败问题汇总
2019/10/17 PHP
ExtJs使用IFrame的实现代码
2010/03/24 Javascript
Javascript简单实现可拖动的div
2013/10/22 Javascript
jquery获取复选框被选中的值
2014/04/10 Javascript
jQuery实现的仿百度,仿谷歌搜索下拉框效果示例
2016/12/30 Javascript
TypeScript入门-基本数据类型
2017/03/28 Javascript
webpack项目调试以及独立打包配置文件的方法
2018/02/28 Javascript
JavaScript中为事件指定处理程序的五种方式分析
2018/07/27 Javascript
JS打印彩色菱形的实例代码
2018/08/15 Javascript
MockJs结合json-server模拟后台数据
2020/08/26 Javascript
微信小程序页面间传递数组对象方法解析
2019/11/06 Javascript
[46:16]2018DOTA2亚洲邀请赛3月30日 小组赛B组 iG VS VP
2018/03/31 DOTA
wxPython中文教程入门实例
2014/06/09 Python
Python安装Imaging报错:The _imaging C module is not installed问题解决方法
2014/08/22 Python
用Python进行一些简单的自然语言处理的教程
2015/03/31 Python
python实现应用程序在右键菜单中添加打开方式功能
2017/01/09 Python
使用Python &amp; Flask 实现RESTful Web API的实例
2017/09/19 Python
Selenium(Python web测试工具)基本用法详解
2018/08/10 Python
解决pycharm的Python console不能调试当前程序的问题
2019/01/20 Python
python自动保存百度盘资源到百度盘中的实例代码
2019/08/26 Python
利用python绘制数据曲线图的实现
2020/04/09 Python
俄罗斯品牌服装和鞋子在线商店:BRIONITY
2020/03/26 全球购物
分布式数据库需要考虑哪些问题
2013/12/08 面试题
物理教师自荐信范文
2013/12/28 职场文书
2014年群众路线党员自我评议
2014/09/24 职场文书
干部个人考察材料
2014/12/24 职场文书
优秀班集体事迹材料
2014/12/25 职场文书
元宵节寄语大全
2015/02/27 职场文书
2015年上半年计生工作总结
2015/03/30 职场文书
婚宴新娘致辞
2015/07/28 职场文书
个人销售励志奋斗口号
2019/12/05 职场文书
浅谈Java实现分布式事务的三种方案
2021/06/11 Java/Android