闭包,函数式编程学习小记
对象是包含行为的数据,闭包是包含数据的行为。
闭包就是能够读取其他函数内部变量的函数,也可以让内部的局部变量通过闭包暴露给外部函数,所以本质上闭包就是将函数内部和函数外部连接起来的一座桥梁。
function f1(){ var n=999; nAdd=function(){n+=1} function f2(){ alert(n); } return f2; } var result=f1(); result(); // 999 nAdd(); result(); // 1000
//f2中用了f1中的局部变量,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。这样就可以达到局部变量在多次调用闭包时候共享的目的。
//这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。
//如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了。 //代码片段一 var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()()); //代码片段二 var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; } }; alert(object.getNameFunc()());
一个介绍js函数式编程的gitbook https://llh911001.gitbooks.io/mostly-adequate-guide-chinese/content/
// 把整个应用里的所有 httpGet 调用都改成这样,可以传递 err 参数。 httpGet('/post/2', function(json, err){ return renderPost(json, err); }); // 写成一等公民函数的形式,要做的改动将会少得多: httpGet('/post/2', renderPost); // renderPost 将会在 httpGet 中调用,想要多少参数都行
// 纯的 var checkAge = function(age) { var minimum = 21; return age >= minimum; }; //我们也可以让 minimum 成为一个不可变(immutable)对象,这样就能保留纯粹性,因为状态不会有变化。要实现这个效果,必须得创建一个对象,然后调用 Object.freeze 方法: var immutableState = Object.freeze({ minimum: 21 });
// 柯里化 curry 的概念很简单:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。 var add = function(x) { return function(y) { return x + y; }; }; var increment = add(1); var addTen = add(10); increment(2); // 3 addTen(2); // 12
// 我们来创建一些 curry 函数享受下(译者注:此处原文是“for our enjoyment”,语出自圣经) var curry = require('lodash').curry; var match = curry(function(what, str) { return str.match(what); }); var filter = curry(function(f, ary) { return ary.filter(f); }); match(/\s+/g, "hello world"); // [ ' ' ] match(/\s+/g)("hello world"); // [ ' ' ] var hasSpaces = match(/\s+/g); // function(x) { return x.match(/\s+/g) } filter(hasSpaces, ["tori_spelling", "tori amos"]); // ["tori amos"] var findSpaces = filter(hasSpaces); // function(xs) { return xs.filter(function(x) { return x.match(/\s+/g) }) } findSpaces(["tori_spelling", "tori amos"]); // ["tori amos"]
//代码组合(compose,以下将称之为组合): var compose = function(f,g) { return function(x) { return f(g(x)); }; }; //让代码从右向左运行,而不是由内而外运行,我觉得可以称之为“左倾”(吁——)。我们来看一个顺序很重要的例子: var head = function(x) { return x[0]; }; var reverse = reduce(function(acc, x){ return [x].concat(acc); }, []); var last = compose(head, reverse); last(['jumpkick', 'roundhouse', 'uppercut']); //=> 'uppercut' // 结合律(associativity) var associative = compose(f, compose(g, h)) == compose(compose(f, g), h); // true
//pointfree 模式指的是,永远不必说出你的数据。咳咳对不起(译者注:此处原文是“Pointfree style means never having to say your data”,源自 1970 年的电影 Love Story 里的一句著名台词“Love means never having to say you're sorry”。) // 非 pointfree,因为提到了数据:word var snakeCase = function (word) { return word.toLowerCase().replace(/\s+/ig, '_'); }; // pointfree var snakeCase = compose(replace(/\s+/ig, '_'), toLowerCase);
TODO 未完待续 https://llh911001.gitbooks.io/mostly-adequate-guide-chinese/content/ch6.html
E-mail: huahuiyang@gmail.com
https://www.linkedin.com/in/huahuiyang/