91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript函數式編程實例分析

發布時間:2022-05-07 13:49:39 來源:億速云 閱讀:93 作者:zzz 欄目:大數據

本篇內容介紹了“JavaScript函數式編程實例分析”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

我理解的函數式編程

我認為函數式編程可以理解為,以函數作為主要載體的編程方式,用函數去拆解、抽象一般的表達式

與命令式相比,這樣做的好處在哪?主要有以下幾點:

  • 語義更加清晰

  • 可復用性更高

  • 可維護性更好

  • 作用域局限,副作用少

基本的函數式編程

下面例子是一個具體的函數式體現

// 數組中每個單詞,首字母大寫// 一般寫法const arr = ['apple', 'pen', 'apple-pen'];for(const i in arr){  const c = arr[i][0];
  arr[i] = c.toUpperCase() + arr[i].slice(1);
}console.log(arr);// 函數式寫法一function upperFirst(word) {  return word[0].toUpperCase() + word.slice(1);
}function wordToUpperCase(arr) {  return arr.map(upperFirst);
}console.log(wordToUpperCase(['apple', 'pen', 'apple-pen']));// 函數式寫法二console.log(arr.map(['apple', 'pen', 'apple-pen'], word => word[0].toUpperCase() + word.slice(1)));

當情況變得更加復雜時,表達式的寫法會遇到幾個問題:

  1. 表意不明顯,逐漸變得難以維護

  2. 復用性差,會產生更多的代碼量

  3. 會產生很多中間變量

函數式編程很好的解決了上述問題。首先參看 函數式寫法一,它利用了函數封裝性將功能做拆解(粒度不***),并封裝為不同的函數,而再利用組合的調用達到目的。這樣做使得表意清晰,易于維護、復用以及擴展。其次利用 高階函數Array.map 代替 for…of 做數組遍歷,減少了中間變量和操作。

而 函數式寫法一 和 函數式寫法二 之間的主要差別在于,可以考慮函數是否后續有復用的可能,如果沒有,則后者更優。

鏈式優化

從上面 函數式寫法二 中我們可以看出,函數式代碼在寫的過程中,很容易造成 橫向延展,即產生多層嵌套,下面我們舉個比較極端點的例子。

// 計算數字之和

// 一般寫法
console.log(1 + 2 + 3 - 4)

// 函數式寫法
function sum(a, b) {  return a + b;
}

function sub(a, b) {  return a - b;
}

console.log(sub(sum(sum(1, 2), 3), 4);

本例僅為展示 橫向延展 的比較極端的情況,隨著函數的嵌套層數不斷增多,導致代碼的可讀性大幅下降,還很容易產生錯誤。

在這種情況下,我們可以考慮多種優化方式,比如下面的 鏈式優化 。

// 優化寫法 (嗯,你沒看錯,這就是 lodash 的鏈式寫法)const utils = {
  chain(a) {this._temp = a;return this;
  },
  sum(b) {this._temp += b;return this;
  },
  sub(b) {this._temp -= b;return this;
  },
  value() {const _temp = this._temp;this._temp = undefined;return _temp;
  }
};console.log(utils.chain(1).sum(2).sum(3).sub(4).value());

這樣改寫后,結構會整體變得比較清晰,而且鏈的每一環在做什么也可以很容易的展現出來。函數的嵌套和鏈式的對比還有一個很好的例子,那就是 回調函數 和 Promise 模式

// 順序請求兩個接口// 回調函數import $ from 'jquery';
$.post('a/url/to/target', (rs) => {  if(rs){
    $.post('a/url/to/another/target', (rs2) => {      if(rs2){
        $.post('a/url/to/third/target');
      }
    });
  }
});// Promiseimport request from 'catta';  // catta 是一個輕量級請求工具,支持 fetch,jsonp,ajax,無依賴request('a/url/to/target')
  .then(rs => rs ? $.post('a/url/to/another/target') : Promise.reject())
  .then(rs2 => rs2 ? $.post('a/url/to/third/target') : Promise.reject());

隨著回調函數嵌套層級和單層復雜度增加,它將會變得臃腫且難以維護,而 Promise 的鏈式結構,在高復雜度時,仍能縱向擴展,而且層次隔離很清晰。

常見的函數式編程模型

閉包(Closure)

可以保留局部變量不被釋放的代碼塊,被稱為一個閉包

閉包的概念比較抽象,相信大家都或多或少知道、用到這個特性

那么閉包到底能給我們帶來什么好處?

先來看一下如何創建一個閉包:

// 創建一個閉包function makeCounter() {  let k = 0;  return function() {return ++k;
  };
}const counter = makeCounter();console.log(counter());  // 1console.log(counter());  // 2

makeCounter 這個函數的代碼塊,在返回的函數中,對局部變量 k ,進行了引用,導致局部變量無法在函數執行結束后,被系統回收掉,從而產生了閉包。而這個閉包的作用就是,“保留住“ 了局部變量,使內層函數調用時,可以重復使用該變量;而不同于全局變量,該變量只能在函數內部被引用。

換句話說,閉包其實就是創造出了一些函數私有的 ”持久化變量“。

所以從這個例子,我們可以總結出,閉包的創造條件是:

  1. 存在內、外兩層函數

  2. 內層函數對外層函數的局部變量進行了引用

閉包的用途

閉包的主要用途就是可以定義一些作用域局限的持久化變量,這些變量可以用來做緩存或者計算的中間量等等。

// 簡單的緩存工具// 匿名函數創造了一個閉包const cache = (function() {  const store = {};  return {get(key) {      return store[key];
    },set(key, val) {
      store[key] = val;
    }
  }
}());

cache.set('a', 1);
cache.get('a');  // 1

上面例子是一個簡單的緩存工具的實現,匿名函數創造了一個閉包,使得 store 對象 ,一直可以被引用,不會被回收。

閉包的弊端

持久化變量不會被正常釋放,持續占用內存空間,很容易造成內存浪費,所以一般需要一些額外手動的清理機制。

高階函數

接受或者返回一個函數的函數稱為高階函數

聽上去很高冷的一個詞匯,但是其實我們經常用到,只是原來不知道他們的名字而已。JavaScript 語言是原生支持高階函數的,因為 JavaScript 的函數是一等公民,它既可以作為參數又可以作為另一個函數的返回值使用。

我們經常可以在 JavaScript 中見到許多原生的高階函數,例如 Array.map , Array.reduce , Array.filter

下面以 map 為例,我們看看他是如何使用的

map (映射)

映射是對集合而言的,即把集合的每一項都做相同的變換,產生一個新的集合

map 作為一個高階函數,他接受一個函數參數作為映射的邏輯

// 數組中每一項加一,組成一個新數組// 一般寫法const arr = [1,2,3];const rs = [];for(const n of arr){
  rs.push(++n);
}console.log(rs)// map改寫const arr = [1,2,3];const rs = arr.map(n => ++n);

上面一般寫法,利用 for...of 循環的方式遍歷數組會產生額外的操作,而且有改變原數組的風險

而 map 函數封裝了必要的操作,使我們僅需要關心映射邏輯的函數實現即可,減少了代碼量,也降低了副作用產生的風險。

柯里化(Currying)

給定一個函數的部分參數,生成一個接受其他參數的新函數

可能不常聽到這個名詞,但是用過 undescore 或 lodash 的人都見過他。

有一個神奇的 _.partial 函數,它就是柯里化的實現

// 獲取目標文件對基礎路徑的相對路徑// 一般寫法const BASE = '/path/to/base';const relativePath = path.relative(BASE, '/some/path');// _.parical 改寫const BASE = '/path/to/base';const relativeFromBase = _.partial(path.relative, BASE);const relativePath = relativeFromBase('/some/path');

通過 _.partial ,我們得到了新的函數 relativeFromBase ,這個函數在調用時就相當于調用 path.relative ,并默認將***個參數傳入 BASE ,后續傳入的參數順序后置。

本例中,我們真正想完成的操作是每次獲得相對于 BASE 的路徑,而非相對于任何路徑。柯里化可以使我們只關心函數的部分參數,使函數的用途更加清晰,調用更加簡單。

組合(Composing)

將多個函數的能力合并,創造一個新的函數

同樣你***次見到他可能還是在 lodash 中,compose 方法(現在叫 flow

// 數組中每個單詞大寫,做 Base64// 一般寫法 (其中一種)const arr = ['pen', 'apple', 'applypen'];const rs = [];for(const w of arr){
  rs.push(btoa(w.toUpperCase()));
}console.log(rs);// _.flow 改寫const arr = ['pen', 'apple', 'applypen'];const upperAndBase64 = _.partialRight(_.map, _.flow(_.upperCase, btoa));console.log(upperAndBase64(arr));

_.flow 將轉大寫和轉 Base64 的函數的能力合并,生成一個新的函數。方便作為參數函數或后續復用。

“JavaScript函數式編程實例分析”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

新巴尔虎右旗| 金寨县| 龙胜| 西峡县| 黎川县| 嘉善县| 阿拉善右旗| 林西县| 岐山县| 洮南市| 扎鲁特旗| 澄江县| 绥棱县| 永顺县| 拉萨市| 左云县| 霞浦县| 喜德县| 通道| 乌鲁木齐县| 敦化市| 辽中县| 平乡县| 广宗县| 晋州市| 黄大仙区| 乃东县| 个旧市| 郸城县| 巴彦县| 中西区| 张家界市| 霸州市| 贵州省| 阿巴嘎旗| 米泉市| 蒲江县| 民和| 汾阳市| 台山市| 顺义区|