本文讲述闭包及柯里化知识点。

一 目录

不折腾的前端,和咸鱼有什么区别

目录
一 目录
二 闭包
三 闭包益处和害处
四 柯里化
 4.1 柯里化举例
 4.2 柯里化益处
 4.3 题目:实现 add(1)(2)(3)
 4.4 题目:实现 compose(foo, bar, baz)('start')
五 题目列表
 5.1 求打印后果 1
 5.2 求打印后果 2
六 参考文献

二 闭包

返回目录

在 JavaScript 中,依据词法作用域的规定,外部函数总是能够拜访其内部函数中申明的变量。

当通过调用一个内部函数返回一个外部函数后,即便该内部函数曾经执行完结了,然而外部函数援用内部函数的变量仍然保留在内存中,咱们就把这些变量的汇合称为闭包。

简略来说:

  • 在函数 A 中还有函数 B,函数 B 调用了函数 A 中的变量,那么函数 B 就称为函数 A 的闭包。

举个例子:

function foo() {  let num = 0;  return function() {    num++;    console.log(num);  };}const f = foo();f(); // 1f(); // 2

这个 num 在返回的函数中存在了,所以每次调用都会 + 1。

三 闭包益处和害处

返回目录

益处:

  1. 缓存。将变量暗藏起来不被 GC 回收。
  2. 实现柯里化。利用闭包个性实现柯里化。

害处:

  1. 内存耗费。闭包产生的变量无奈被销毁。
  2. 性能问题。因为闭包外部变量优先级高于内部变量,所以须要多查找作用域链的一个档次,肯定水平影响查找速度。

四 柯里化

返回目录

柯里化(Currying)是把承受多个参数的函数转变为繁多参数的函数,并且返回承受余下的参数且返回后果的新函数的技术。

简略来说

  1. 通过闭包治理
  2. 反对链式调用
  3. 每次运行返回一个 function

即:通过将多个参数换成一个参数,每次运行返回新函数的技术

4.1 柯里化举例

返回目录

一般的 add 函数

function add (a, b) {  return a + b;}add(1, 2);
柯里化函数
function curryingAdd (x) {  return function(y) {    return x + y;  }}curryingAdd(x)(y);

哎,这样不是节约程序员工夫么?

不急,咱们持续往下面看。

4.2 柯里化益处

返回目录
  1. 参数复用
  2. 提前确认
  3. 提早运行
参数复用
// 正则表达式// 校验数字let numberReg = /[0-9]+/g;// 校验小写字母let stringReg = /[a-z]+/g;// currying 后function curryingCheck(reg) {  return function(txt) {    return reg.test(txt);  }}// 校验数字let checkNumber = curryingCheck(numberReg);let checkString = curryingCheck(stringReg);// 应用console.log(checkNumber('13888888888')); // trueconsole.log(checkString('jsliang')); // true

利用闭包实现柯里化。

4.3 题目:实现 add(1)(2)(3)

返回目录
// 实现一个 add 办法,使计算结果可能满足以下预期add(1)(2)(3) = 6;add(1, 2, 3)(4) = 10;add(1)(2)(3)(4)(5) = 15;

答:

function add () {  const numberList = Array.from(arguments);  // 进一步收集残余参数  const calculate = function() {    numberList.push(...arguments);    return calculate;  }  // 利用 toString 隐式转换,最初执行时进行转换  calculate.toString = function() {    return numberList.reduce((a, b) => a + b, 0);  }  return calculate;}// 实现一个 add 办法,使计算结果可能满足以下预期console.log(add(1)(2)(3)); // 6console.log(add(1, 2, 3)(4)); // 10;console.log(add(1)(2)(3)(4)(5)); // 15;

4.4 题目:实现 compose(foo, bar, baz)('start')

返回目录
function foo(...args) {  console.log(args[0]);  return 'foo';}function bar(...args) {  console.log(args[0]);  return 'bar';}function baz(...args) {  console.log(args[0]);  return 'baz';}function compose() {  // 闭包元素 - 函数列表  const list = Array.from(arguments);  // 闭包元素 - 函数列表执行地位  let index = -1;  // 闭包元素 - 上一个函数的返回  let prev = '';  // 返回闭包函数  const doNext = function() {    index++; // 索引值累加    // 一开始没有上一个元素时,获取第二个括号的值    if (!prev) {      prev = arguments[0];    }    // 设置前一个后果为以后函数返回    prev = list[index](prev);    // 递归调用    if (index < list.length - 1) {      doNext(index + 1);    }  };  // 第一次返回闭包函数  return doNext;}compose(foo, bar, baz)('start');

五 题目列表

返回目录

5.1 求打印后果 1

返回目录
function test() {  var n = 4399;  function add() {    n++;    console.log(n);  }  return {    n,    add  };};var result = test();var result2 = test();result.add(); // 输入啥result.add(); // 输入啥console.log(result.n); // 输入啥result2.add(); // 输入啥

抉择:

  • A:4400 4401 4399 4400
  • B:4400 4401 4401 4402
  • C:4400 4400 4399 4400
  • D:4400 4401 4399 4402
  • E:4400 4401 4401 4400

答案:A

5.2 求打印后果 2

返回目录
function Foo() {  var i = 0;  return function() {    console.log(i++);  }}var f1 = Foo();var f2 = Foo();f1();f1();f2();

请抉择:

  • A:0 1 0
  • B:0 1 2
  • C:0 0 0
  • D:0 0 2

答案:A

起因:f1 每次执行会产生闭包,而后 i++ 是先赋值后展现。

六 参考文献

返回目录
  • [x] 详解JS函数柯里化【浏览倡议:20min】
  • [x] 编写add函数 而后 add(1)(2)(3)(4) 输入10 再思考拓展性【浏览倡议:10min】
  • [x] 发现 JavaScript 中闭包的弱小威力【浏览倡议:20min】
  • [x] JavaScript闭包的底层运行机制【浏览倡议:20min】
  • [x] 我从来不了解JavaScript闭包,直到有人这样向我解释它【浏览倡议:10min】
  • [x] 发现 JavaScript 中闭包的弱小威力【浏览倡议:10min】
  • [x] JavaScript闭包的底层运行机制【浏览倡议:20min】
  • [x] 我从来不了解JavaScript闭包,直到有人这样向我解释它...【浏览倡议:10min】
  • [x] 破解前端面试(80% 应聘者不及格系列):从闭包说起【浏览倡议:10min】

<br/>jsliang 的文档库由 梁峻荣 采纳 常识共享 署名-非商业性应用-雷同形式共享 4.0 国内 许可协定 进行许可。<br/>基于 https://github.com/LiangJunrong/document-library 上的作品创作。<br/>本许可协定受权之外的应用权限能够从 https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 处取得。