《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 相关文章推荐
Javascript 构造函数 实例分析
Nov 26 Javascript
ExtJS 工具栏 分页事件参数
Mar 05 Javascript
javascript结合Canvas 实现简易的圆形时钟
Mar 11 Javascript
使用JavaScript 实现的人脸检测
Mar 24 Javascript
谈谈JavaScript中function多重理解
Aug 28 Javascript
javascript绘制漂亮的心型线效果完整实例
Feb 02 Javascript
功能强大的Bootstrap组件(结合js)
Aug 03 Javascript
原生JS实现移动端web轮播图详解(结合Tween算法造轮子)
Sep 10 Javascript
用node.js写一个jenkins发版脚本
May 21 Javascript
一看就会的vuex实现登录验证(附案例)
Jan 09 Javascript
微信小程序实现下拉加载更多商品
Dec 29 Javascript
vue el-table实现递归嵌套的示例代码
Aug 14 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
实现树状结构的两种方法
2006/10/09 PHP
smarty模板引擎基础知识入门
2015/03/30 PHP
PHP实现登陆并抓取微信列表中最新一组微信消息的方法
2017/07/10 PHP
laravel 修改记住我功能的cookie保存时间的方法
2019/10/14 PHP
php进程(线程)通信基础之System V共享内存简单实例分析
2019/11/09 PHP
解决jquery的.animate()函数在IE6下的问题
2010/12/03 Javascript
关于jQuery中的end()使用方法
2011/07/10 Javascript
jquery 笔记 事件
2011/11/02 Javascript
jQuery实现文本框输入同步的方法
2015/06/20 Javascript
学习javascript面向对象 javascript实现继承的方式
2016/01/04 Javascript
JavaScript中的数组遍历forEach()与map()方法以及兼容写法介绍
2016/05/19 Javascript
js鼠标单击和双击事件冲突问题的快速解决方法
2016/07/11 Javascript
基于Node.js模板引擎教程-jade速学与实战1
2017/09/17 Javascript
详解JS函数stack size计算方法
2018/06/18 Javascript
JS 音频可视化插件Wavesurfer.js的使用教程
2018/10/31 Javascript
vue+iview/elementUi实现城市多选
2019/03/28 Javascript
用PyQt进行Python图形界面的程序的开发的入门指引
2015/04/14 Python
python字典基本操作实例分析
2015/07/11 Python
python实现八大排序算法(1)
2017/09/14 Python
Caffe均值文件mean.binaryproto转mean.npy的方法
2018/07/09 Python
PyQt5 加载图片和文本文件的实例
2019/06/14 Python
python用quad、dblquad实现一维二维积分的实例详解
2019/11/20 Python
Python tensorflow实现mnist手写数字识别示例【非卷积与卷积实现】
2019/12/19 Python
python异步Web框架sanic的实现
2020/04/27 Python
Python3爬虫中pyspider的安装步骤
2020/07/29 Python
css3气泡 css3关键帧动画创建的动态通知气泡
2013/02/26 HTML / CSS
Silk’n激光脱毛器官网:silkn.com
2016/10/06 全球购物
俄罗斯运动鞋商店:Sneakerhead
2018/05/10 全球购物
便利店投资的创业计划书
2014/01/12 职场文书
学习经验演讲稿
2014/05/10 职场文书
求职信内容怎么写
2014/05/26 职场文书
人民检察院起诉书
2015/05/20 职场文书
2016年三八红旗手先进事迹材料
2016/02/26 职场文书
如何书写先进事迹材料?
2019/07/02 职场文书
CSS 左边固定宽右边自适应的6种方法
2022/05/15 HTML / CSS
Django框架中模型的用法
2022/06/10 Python