JavaScript 函数式编程读书笔记1
概述
这是我读《javascript函数式编程》的读书笔记,供以后开发时参考,相信对其他人也有用。
说明:虽然本书是基于underscore.js库写的,但是其中的理念和思考方式都讲的很好,值得一读。不过如果不熟悉underscore.js库的话,读起来会有点困难。
从一段代码说起
由于parsInt函数有2个参数,所以下面的代码会得出意想不到的结果:
[3.5, 5.3, 9.8, 13.4, 16.9].map(parseInt);
//输出 [3, NaN, NaN, 1, 1]
原因是map里面的函数可以带有3个参数,第一个是值,第二个是index,第三个是map方法的调用者。
所以如果要对数组的每一个元素取整要怎么做呢?一个方法是把parseInt封装起来,实例如下:
const curry1 = func => (x) => func(x);
[3.5, 5.3, 9.8, 13.4, 16.9].map(curry1(parseInt));
//输出: [3, 5, 9, 13, 16]
这种以函数为一等公民的编程就是函数式编程。其中curry1接受一个函数参数,并且返回一个函数,这样的函数称为高阶函数。谷歌的闭包编译器能够极大的优化函数式编程的代码。
函数式编程
什么是函数式编程?
- 一个对“存在”的抽象函数的定义。
- 一个建立在存在函数之上的,对“真”的抽象函数的定义。
- 通过其它函数来使用上面两个函数,以实现更多的行为。
//对“存在”的定义
function existy(x) { return x!= null; }
//对“真”的定义
function truthy(x) { return (x !== false) && existy(x); }
动态作用域
js中的this引用的就是动态作用域,在不同的函数中,被不同的对象调用,它所指向的对象不同。它是通过apply和call直接操作的,比如如下代码:
const banana = 'banana';
function returnThis() {
return this;
}
returnThis.apply(banana); //输出'banana'
returnThis.call(banana); //输出'banana'
但是在事件中,常常会丢失this,所以我们用bind来绑定this到当前作用域。
const bindThis = returnThis.bind(banana);
bindThis(); //输出'banana'
值得注意的是,bind是惰性的,不像apply或者call那样会立即执行函数。另外,bind还可以用来制造柯里化:
function add(x, y) {
return x + y;
}
const add3 = add.bind(null, 3);
add3(7); //输出10
函数作用域
函数作用域会隐式地把var声明移到函数的顶部,这样做的意义是,函数内定义的变量对函数内任何一段代码都是可见的。
接下来我们来展示,如何用this这个动态作用域来模拟函数作用域。技巧在于用call或者apply绑定函数的作用域。
function f() {
this['a'] = 200;
return this['a'] + this['b'];
}
var global = {'b': 2};
f.call({ ...global }); //输出202
global; //输出{'b': 2}
可以看到,我们复制了一份当前的作用域,并且把它传给了f函数,这样f函数可以调用外部作用域的变量,并且不会污染外部作用域。
这其实就是函数作用域的深层机制。
闭包
这个观点非常有趣:闭包背后的原理是,如果一个函数包含内部函数,那么它们都可以看到其中声明的变量,这些变量被称为“自由变量”。这些变量可以被内部函数“捕获”,然后从renturn中实现“越狱”,以供以后使用。
值得一提的是,利用闭包可以捕获的不仅仅是变量,参数甚至是函数都可以被捕获。
既然闭包捕获了变量,参数或者函数,那么如果在闭包捕获他们之后,他们的值发生了改变,闭包里面的捕获的值会跟着改变吗?我们来看看下面的代码:
function complement(func) {
return function() {
return !func.apply(null, arguments);
}
}
function isEven(n) { return (n%2) === 0}
const isOdd = complement(isEven);
isOdd(23); //输出true
isOdd(24); //输出false
//改变isEven函数
function isEven(n) { return false}
//isOdd不变
isOdd(23); //输出true
isOdd(24); //输出false
上面这段代码表明,捕获的函数不会改变。如果捕获的是变量呢?
var a = 2;
function f(x) {
return function() {
return x;
}
}
var g = f(a);
g(); //输出2
a = 5;
g(); //输出2
var b = {c:3};
var h = f(b);
h(); //输出{c:3}
b.c = 5;
h(); //输出{c:5}
从上面的代码可以看出,如果捕获的是基本类型变量,则不会改变;如果捕获的是对象,那么会改变。
思考一下原因。其实闭包捕获的是函数作用域,而根据上面函数作用域的讨论,函数作用域会把外部作用域和内部作用域的变量浅复制一遍,所以出现了上面的情况。
JavaScript 函数式编程读书笔记1的更多相关文章
- JavaScript 函数式编程读书笔记2
概述 这是我读<javascript函数式编程>的读书笔记,供以后开发时参考,相信对其他人也有用. 说明:虽然本书是基于underscore.js库写的,但是其中的理念和思考方式都讲的很好 ...
- Node.js高级编程读书笔记Outline
Motivation 世俗一把,看看前端的JavaScript究竟能做什么. 顺便检验一下自己的学习能力. Audience 想看偏后台的Java程序员关于前端JavaScript的认识的职业前端工程 ...
- 转:JavaScript函数式编程(三)
转:JavaScript函数式编程(三) 作者: Stark伟 这是完结篇了. 在第二篇文章里,我们介绍了 Maybe.Either.IO 等几种常见的 Functor,或许很多看完第二篇文章的人都会 ...
- 转: JavaScript函数式编程(二)
转: JavaScript函数式编程(二) 作者: Stark伟 上一篇文章里我们提到了纯函数的概念,所谓的纯函数就是,对于相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用,也不依赖外部环 ...
- 转:JavaScript函数式编程(一)
转:JavaScript函数式编程(一) 一.引言 说到函数式编程,大家可能第一印象都是学院派的那些晦涩难懂的代码,充满了一大堆抽象的不知所云的符号,似乎只有大学里的计算机教授才会使用这些东西.在曾经 ...
- python高级编程读书笔记(一)
python高级编程读书笔记(一) python 高级编程读书笔记,记录一下基础和高级用法 python2和python3兼容处理 使用sys模块使程序python2和python3兼容 import ...
- C++Windows核心编程读书笔记
转自:http://www.makaidong.com/%E5%8D%9A%E5%AE%A2%E5%9B%AD%E6%96%87/71405.shtml "C++Windows核心编程读书笔 ...
- 一文带你了解JavaScript函数式编程
摘要: 函数式编程入门. 作者:浪里行舟 Fundebug经授权转载,版权归原作者所有. 前言 函数式编程在前端已经成为了一个非常热门的话题.在最近几年里,我们看到非常多的应用程序代码库里大量使用着函 ...
- javascript函数式编程和链式优化
1.函数式编程理解 函数式编程可以理解为,以函数作为主要载体的编程方式,用函数去拆解.抽象一般的表达式 与命令式相比,这样做的好处在哪?主要有以下几点: (1)语义更加清晰 (2)可复用性更高 (3) ...
随机推荐
- ReactiveX 学习笔记(20)使用 RxJava + RxBinding 进行 GUI 编程
课题 程序界面由3个文本编辑框和1个文本标签组成. 要求文本标签实时显示3个文本编辑框所输入的数字之和. 文本编辑框输入的不是合法数字时,将其值视为0. 3个文本编辑框的初值分别为1,2,3. 创建工 ...
- django内置分页功能扩展
实现自定制页码数类型class myPaginator(Paginator): def __init__(self,curr_page,per_page_num,*args,**kwargs): se ...
- Github(远程仓库) 2
远程仓库之前就添加好了 今天弄了简单的查看远程库,提取远程库,在线修改以及本地更新修改,推送到远程仓库,删除远程仓库,参考http://www.runoob.com/git/git-remote-re ...
- 使用JavaMail发送邮件-从FTP读取图片并添加到邮件正文发送
业务分析: 最近工作需要,需要从FTP读取图片内容,添加到邮件正文发送.发送邮件正文,添加附件采用Spring的MimeMessageHelper对象来完成,添加图片也将采用MimeMessageHe ...
- flash/flex builder在IE中stage.stageWidth始终为0的解决办法
这应该是IE的bug,解决办法: 原作者:菩提树下的杨过出处:http://yjmyzz.cnblogs.com stage.align=StageAlign.TOP_LEFT; stage.scal ...
- windows 远程连接“发生身份验证错误 要求的函数不受支持”
Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\P ...
- C语言变量声明内存分配
转载: C语言变量声明内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)— 程序运行时由编译器自动分配,存放函数的参数值,局部变量的值等.其操作方式类似于数据结 ...
- 322. Coin Change选取最少的硬币凑整-背包问题变形
[抄题]: You are given coins of different denominations and a total amount of money amount. Write a fun ...
- 为了应对异常情况,提供最原始的python第三方库的安装方法:手动安装。往往是Windows用户需要用到这种方法。
进入pypi.python.org,搜索你要安装的库的名字,这时候有3中可能: 第一种是exe文件,这种最方便,下载满足你的电脑系统和python环境的对应的exe,再一路点击next就可以安装. 第 ...
- 三 分析easyswoole源码(启动服务&TableManager,略提及Cache工具的原理)
前文连接,讲了es是如何启动swoole服务的. 里面有一个工具类TableManager.这个类为了处理进程间数据共享.是对swoole_table的一层封装swoole_table一个基于共享内存 ...