<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                >[success] # 純函數 1. **純函數**存在于函數式編程,js 符合函數式編程的范式,因此也具備**純函數的概念** 2. 純函數定義: 2.1. 相同的**輸入**永遠會得到相同的**輸出**,站在數學的角度來說的(用來描述輸入和輸出之間的關系),**y = f(x)**,簡單的說就是對于每套輸入,都存在一個輸出。一個函數會接受輸入,并返回相對應的輸出并且相同輸入總是會**返回相同的輸出** * 純函數相同的輸入永遠會得到相同的輸出 ![](https://img.kancloud.cn/ed/6e/ed6eca1daafc9c6c7510c1877de09a6b_250x165.png) * 就不是函數輸入值 5 指向了多個輸出,注意他連函數都不是 ![](https://img.kancloud.cn/0a/65/0a6537492e4352b563da4fbfd4711226_251x160.png) 2.2. **函數的輸出和輸入**值以外的其他**隱藏信息或狀態無關**,也和由I/O設備產生的外部輸出無關 2.3. 該函數不能有語義上可觀察的**函數副作用** * **總結** * 一個函數只有在給出相同輸入,總是產生相同輸出的時候,才是純函數 * 函數在執行過程中,不能產生副作用 >[danger] ##### 副作用 1. **副作用**(side effect)是醫學的一個概念,經常說吃什么藥本來是為了治病,可能會產生一些其他的**副作用**;在計算機表示在執行**一個函數時**,除了**返回函數值之外**,還對調用函數產生了**附加的影響**,比如**修改了全局變量**,**修改參數或者改變外部的存儲** 2. **副作用**也使得方法通用性下降**不適合擴展和可重用性**,同時副作用會給程序中帶來安全隱患給程序帶來不確定性,但是副作用不可能完全禁止,盡可能控制它們在可控范圍內發生。 3. 常見的副作用**配置文件,數據庫,用戶輸入** 這些外部因素 ~~~ // 不純的 let mini = 18 // 外部不可控的 function checkAge(age) { return age >= mini } // 純的 function checkAge(age) { let mini = 18 // 在內部可控的 return age >= mini } ~~~ ~~~ let totalApples = 5 const applesBought = 5 const addApplesToTotal = (num) => { totalApples = applesBought + totalApples + num return totalApples } // 每次輸入相同 輸出卻不同不是純函數 console.log(addApplesToTotal(10)) // 20 console.log(addApplesToTotal(10)) // 35 ~~~ >[danger] ##### slice 和 splice 1. slice 輸入0,3無論調用多少次返回值的結果都是一樣的,但是splice就不是這樣 ~~~ let numbers = [1, 2, 3, 4, 5] // 純函數 numbers.slice(0, 3)// => [1, 2, 3] numbers.slice(0, 3)// => [1, 2, 3] numbers.slice(0, 3)// => [1, 2, 3] // 不純的函數 numbers.splice(0, 3)// => [1, 2, 3] numbers.splice(0, 3)// => [4, 5] numbers.splice(0, 3)// => [] ~~~ >[info] ## 純函數好處 1. 保證了函數的純度,只是單純實現自己的業務邏輯即可,不需要關心傳入的內容是如何獲得的或者依賴其他的外部變量是否已經發生了修改 2. 你確定你的輸入內容不會被任意篡改,并且自己確定的輸入,一定會有確定的輸出 3. **可緩存**因為純函數,相同的輸入總是對應相同的輸出,因此我們可以利用這個做緩存,如果10 = f(5)輸入5會得到10,那么下次輸入5的時候經過上次已經知道結果是10,可以變相跳過函數中間過程 4. **可測試**純函數讓測試更方便,因為不受外界干擾 >[danger] ##### 做一個緩存函數用來 -- 緩存純函數 ~~~ function memoize(f) { let cache = {} return function () { let arg_str = JSON.stringify(arguments) cache[arg_str] = cache[arg_str] || f.apply(f, arguments) return cache[arg_str] } } // 需要定義一個純函數 // 相同的輸入一定會有相同的輸入 function getArea(r) { console.log('如果是輸入相同我執行一次,因為下次走了緩存') return Math.PI * r * r } // 用緩存的函數 緩存一下這個純函數 let getAreaWithMemory = memoize(getArea) console.log(getAreaWithMemory(5)) console.log(getAreaWithMemory(5)) // 打印結果: 如果是輸入相同我執行一次,因為下次走了緩存 78.53981633974483 78.53981633974483 ~~~ >[info] ## 純函數在開發過程中 * 下面函數都依賴**el**元素,如果環境改變了 此時函數的結果也會更改,需要將其構建一個嚴格的純函數,是具有**確定性**、**無副作用**,**冪等**的特點,不管什么時候調用,只要參數確定,返回值就確定 ~~~ export function setStyle(el, key, value) { el.style[key] = value; } export function setStyles(els, key, value) { els.forEach(el => setStyle(el, key, value)); } ~~~ * 雖然`setStyle`依然不是純函數,但是`batch`是一個純函數,想具備類似功能函數只要去調用`batch` ~~~ function batch(fn) { return function (subject, ...args) { if(Array.isArray(subject)) { return subject.map((s) => { return fn.call(this, s, ...args); }); } return fn.call(this, subject, ...args); }; } const setStyle = batch((el, key, value) => { el.style[key] = value; }); const items = document.querySelectorAll('li:nth-child(2n+1)'); setStyle([...items], 'color', 'red'); ~~~ * 這種封裝一次,和下面直接這種將需求寫死有什么區別 ~~~ function setStyle(el, key, value) { if(Array.isArray(el)) { return el.forEach((e) => { setStyle(e, key, value); // 直接寫死進行調用 }); } el.style[key] = value; } ~~~ * 區別在于實際工作中不僅僅只會set 賦值操作,也可能有remove 刪除操作等等,我們代碼可能就變成下面 ~~~ function addState(el, state) { if(Array.isArray(el)) { return el.forEach((e) => { addState(e, state); }); } removeState(el, state); el.className = el.className ? `${el.className} ${state}` : state; } function removeState(el, state) { if(Array.isArray(el)) { return el.forEach((e) => { removeState(e, state); }); } el.className = el.className.replace(new RegExp(`(^|\\s)${state}(\\s|$)`, 'g'), ''); } ~~~ * 相比較 同一抽象后進行處理的代碼 ~~~ // 統一的批量化處理 addState = batch(addState); removeState = batch(removeState); ~~~ >[danger] ##### 參考 [前端工程師進階 10 日談](https://juejin.cn/book/6891929939616989188)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看