實務上如何使用 Closure ?

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

内容简介: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 ?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

刷屏

刷屏

[美] 凯文•阿洛卡 / 侯奕茜、何语涵 / 中信出版社 / 2018-10-1 / 68.00

1. YouTube流行趋势经理,解密如何打造爆款视频 在视频时代,制造互动,才能创造潮流 用户不再是被动的观众,而是主动的传播者 2. 《刷屏》以行内人视角解读: 病毒视频 粉丝经济 网红产业 平台如何为内容创作者赋能 3. 你是否常常被病毒视频刷屏?你是否觉得很多网红火爆到“无法用常理解释”? 视频时代已经到来,我们每天观看网络......一起来看看 《刷屏》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具