實務上如何使用 Closure ?

栏目: JavaScript · 发布时间: 6年前

内容简介:Closure 是 ECMAScript 的代表性功能,也是 Functional Programming 的基礎,很多神妙的 FP 機制都是由 Closure 展開,善用 Closure 將使得程式碼更為精簡,可讀性更高,也更容易維護。ECMAScript 2015藉由 function 的 parameter 建立新的 function,而新的 function 則藉由 Closure 讀取原 function 的 parameter

Closure 是 ECMAScript 的代表性功能,也是 Functional Programming 的基礎,很多神妙的 FP 機制都是由 Closure 展開,善用 Closure 將使得程式碼更為精簡,可讀性更高,也更容易維護。

Version

ECMAScript 2015

Function Factory

藉由 function 的 parameter 建立新的 function,而新的 function 則藉由 Closure 讀取原 function 的 parameter

Higher Order Function

const data = [1, 2, 3];

console.log(data.map(x => x * 2));
console.log(data.map(x => x * 2 + 1));

ECMAScript 提供很多 Higher Order Function,如 Array.prototypesetTimeout() ,我們會傳入 Arrow Function。

若 Arrow Function 有重複,或者類似規則的 Arrow Function 不斷出現,則可藉由 Closure 抽出 Function Factory。

const data = [1, 2, 3];

const makeMapper = (a, b) => x => a * x + b;

console.log(data.map(makeMapper(2, 0)));
console.log(data.map(makeMapper(2, 1)));

抽出 makeMappr() ,藉由傳入不同 argument 給 makeMapper() 產生不同的 Arrow Fuction 給 map()

實務上如何使用 Closure ?

Object Method

const foo = {
  func1: x => 2 * x + 3,
  func2: x => 3 * x + 1,
};

console.log(foo.func1(1));
console.log(foo.func2(1));

當使用 Object Literal 定義 method 時,若 method 有重複,或者類似規則的 method 不斷出現,則可藉由 Closure 抽出 Function Factory。

const makeFunc = (a, b) => x => a * x + b;

const foo = {
  func1: makeFunc(2, 3),
  func2: makeFunc(3, 1),
};

console.log(foo.func1(1));
console.log(foo.func2(1));

func1()func2() 可藉由 makeFunc() 產生。

抽出 makeFunc() ,藉由傳入不同 argument 給 makeFunc() 產生不同的 method。

實務上如何使用 Closure ?

Factory Function 是是由 function 建立 object;而 Function Factory 是由 function 建立 function

Partial Application

Function 若只傳部分 argument 進去,則會回傳新的 function;直到所有 argument 都傳遞完全才會開始求值

const func = (x, y, z) => 2 * x + 3 * y + z;

console.log(func(10, 3, 2));
console.log(func(10, 1, 2));
console.log(func(10, 4, 2));

func 為多 argument 的 function,但實務上發現第 1 個 argument 都一樣,只有第 2 個與第 3 個 argument 在改變。

const func = x => (y, z) => 2 * x + 3 * y + z;

const func1 = func(10);

console.log(func1(3, 2));
console.log(func1(1, 2));
console.log(func1(4, 2));

將第 1 個 argument 傳入 func() 即可,會傳回新的 func1()

然後只需將第 2 個與第 3個 argument 傳入 func1() 即可得到結果,不需再重複傳入第一個 argument。

實務上如何使用 Closure ?

Currying

將原本 n 個 argument 的 function 改用 n 個 1 個 argument 的 function 所構成

const func = (x, y, z) => 2 * x + 3 * y + z;

console.log(func(1, 1, 1));
console.log(func(1, 1, 2));
console.log(func(1, 2, 2));
console.log(func(1, 2, 3));
console.log(func(1, 3, 4));

Partial Application 固然靈活,但只能針對特定 argument 組合回傳 function,若所有 funtion 都只有 1 個 argument,則 argument 的排列組合是最靈活的。

const func = x => y => z => 2 * x + 3 * y + z;

const func1 = func(1)(1);
const func2 = func(1)(2);

console.log(func1(1));
console.log(func1(2));
console.log(func2(2));
console.log(func2(3));
console.log(func(1)(3)(4));

無論需求怎麼變,都能任意湊出想要的 function。

實務上如何使用 Closure ?

Encapsulation

const foo = {
  name: 'Sam',
  sayHello: function() {
    return `Hello ${this.name}`;
  },
};

console.log(foo.sayHello());

使用 Object Literal 建立 object,所有的 property 都是 public 的,完全沒有任何 Encapsulation 可言,該如何如 OOP 有 private field 呢 ?

const foo = (function(name) {
  return {
    sayHello: () => `Hello ${name}`,
  }
}('Sam'));

console.log(foo.sayHello());

使用 Closure + IIFE, name 可如 OOP 的 constructor 般傳入設定初始值,重點是 name 被封裝在內部,外界無法更改。

實務上如何使用 Closure ?

const foo = (function(name) {
  const addTitle = name => `Mr. ${name}`;
  const title = addTitle(name);

  return {
    sayHello: () => `Hello ${title}`,
  }
}('Sam'));

console.log(foo.sayHello());

也能在 Anonymous Function 增加 variable 與 function,相當於 OOP 的 private field 與 private method。

實務上如何使用 Closure ?

Memorization

將耗時的運算結果存起來,若第二次執行該 function,則直接從 cache 讀出

const isPrime = value => {
  if (!isPrime.cache) isPrime.cache = {};
  if (isPrime.cache[value]) return isPrime.cache[value];

  let prime = value !== 1;
  for(let i = 2; i < value; i++) {
    if (value % 2 === 0) {
      prime = false;
      break;
    }
  }

  return isPrime.cache[value] = prime;
};

console.log(isPrime(13));

判斷質數 是很耗時的運算,我們希望能將運算過的結果 cache 下來,可直接對 isPrime() 新增 cache property,若 cache 有值則直接回傳,若 cache 無值才運算。

實務上如何使用 Closure ?

const isPrime = (() => {
  let cache = {};

  return value => {
    if (cache[value]) return cache[value];

    let prime = value !== 1;
    for(let i = 2; i < value; i++) {
      if (value % 2 === 0) {
        prime = false;
        break;
      }
    }

    return cache[value] = prime;
  };
})();

console.log(isPrime(13));

Memorization 另一種實現方式是利用 Closure,這種方式的優點在於 Encapsulation,cache 不會暴露在外被修改。

實務上如何使用 Closure ?

Conclusion

  • Closure 是 FP 的基礎,實務上最常使用的是 Function Factory
  • 透過 Closure + IIFE,也能以 function 實現 OOP 的 Encapsulation

以上所述就是小编给大家介绍的《實務上如何使用 Closure ?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

那些让文案绝望的文案

那些让文案绝望的文案

小马宋 / 北京联合出版公司 / 2015-10 / 45

什么文案60年前就在使用互联网思维? 什么文案让一辆小车在崇尚大车的国度畅销不衰? 什么文案让做文案的人产生“既生瑜何生亮”的绝望? 没错,它是甲壳虫。 远在上世纪五六十年代,这些文案让这辆不起眼的小车畅销不衰。 它的文案风趣而又言之凿凿,它的文案机智而又无可辩驳。 它充满自黑精神,善于借势时事热点,懂得乖巧卖萌,也是天生的段子手。 为了让国内读者一睹这一......一起来看看 《那些让文案绝望的文案》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试