闭包,函数式编程学习小记

时间:2022-12-30 22:41:27

对象是包含行为的数据,闭包是包含数据的行为。

闭包就是能够读取其他函数内部变量的函数,也可以让内部的局部变量通过闭包暴露给外部函数,所以本质上闭包就是将函数内部和函数外部连接起来的一座桥梁。

 

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