《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 组合form元素为json格式,asp.net反序列化
Jul 09 Javascript
原生Js实现按的数据源均分时间点幻灯片效果(已封装)
Dec 28 Javascript
禁止IE用右键的JS代码
Dec 30 Javascript
JavaScript实现在标题栏上显示当前日期的方法
Mar 19 Javascript
VUE2实现事件驱动弹窗示例
Oct 21 Javascript
深入理解Vue 单向数据流的原理
Nov 09 Javascript
基于jquery实现五星好评
Nov 18 jQuery
详解vue项目的构建,打包,发布全过程
Nov 23 Javascript
vue基础知识--axios合并请求和slot
Jun 04 Javascript
Vue在H5 项目中使用融云进行实时个人单聊通讯
Dec 14 Vue.js
vue二选一tab栏切换新做法实现
Jan 19 Vue.js
vue使用watch监听属性变化
Apr 30 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
冰滴咖啡制作步骤
2021/03/03 冲泡冲煮
台湾中原大学php教程孙仲岳主讲
2008/01/07 PHP
php过滤HTML标签、属性等正则表达式汇总
2014/09/22 PHP
JavaScript通过prototype给对象定义属性用法实例
2015/03/23 Javascript
js中对函数设置默认参数值的3种方法
2015/10/23 Javascript
Angular.JS利用ng-disabled属性和ng-model实现禁用button效果
2017/04/05 Javascript
解决Extjs下拉框不显示的问题
2017/06/21 Javascript
Vue2 Vue-cli中使用Typescript的配置详解
2017/07/24 Javascript
Vue表单类的父子组件数据传递示例
2018/05/03 Javascript
javascript验证form表单数据的案例详解
2019/03/25 Javascript
微信小程序 WXML节点信息查询详解
2019/07/29 Javascript
vue框架制作购物车小球动画效果实例代码
2019/09/26 Javascript
vue实现表单录入小案例
2019/09/27 Javascript
解决vue-photo-preview 异步图片放大失效的问题
2020/07/29 Javascript
python实现在pickling的时候压缩的方法
2014/09/25 Python
Python中List.count()方法的使用教程
2015/05/20 Python
Python-嵌套列表list的全面解析
2016/06/08 Python
Python端口扫描简单程序
2016/11/10 Python
Python中的pack和unpack的使用
2018/03/12 Python
基于scrapy的redis安装和配置方法
2018/06/13 Python
spark dataframe 将一列展开,把该列所有值都变成新列的方法
2019/01/29 Python
Python 把序列转换为元组的函数tuple方法
2019/06/27 Python
django 通过URL访问上传的文件方法
2019/07/28 Python
python tkinter基本属性详解
2019/09/16 Python
Python flask框架如何显示图像到web页面
2020/06/03 Python
python3读取autocad图形文件.py实例
2020/06/05 Python
PHP笔试题
2012/02/22 面试题
好人好事演讲稿
2014/09/01 职场文书
2016自主招生校长推荐信范文
2015/03/23 职场文书
交通事故赔偿起诉书
2015/05/20 职场文书
公司的力量观后感
2015/06/05 职场文书
2016秋季小学开学寄语
2015/12/03 职场文书
2016年幼儿园庆六一开幕词
2016/03/04 职场文书
详解Django的MVT设计模式
2021/04/29 Python
Python基础之hashlib模块详解
2021/05/06 Python
ant design charts 获取后端接口数据展示
2022/05/25 Javascript