<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] # 抽象函數 * 函數式編程是js天生具備的,如何使用函數式編程將過程抽象出來 >[info] ## 第一個案例 -- 連續點擊問題 有個todo-list,當我們點擊時候對應todo 事項會被移除,為了做的效果更好看,增加了動畫效果,導致連續點擊時候會出現報錯,如下 ![](https://img.kancloud.cn/c3/cc/c3ccb27adfbe295dc01552279336765d_891x703.gif) ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> ul { padding: 0; margin: 0; list-style: none; } li button { border: 0; background: transparent; cursor: pointer; outline: 0 none; } li.completed { transition: opacity 2s; opacity: 0; } li button:before { content: '??'; } li.completed button:before { content: '?'; } </style> </head> <body> <ul> <li><button></button><span>任務一:學習HTML</span></li> <li><button></button><span>任務二:學習CSS</span></li> <li><button></button><span>任務三:學習JavaScript</span></li> </ul> </body> <script> const list = document.querySelector('ul') const buttons = list.querySelectorAll('button') buttons.forEach((button) => { button.addEventListener( 'click', (evt) => { const target = evt.target target.parentNode.className = 'completed' setTimeout(() => { // 觸發動畫效果移除 class list.removeChild(target.parentNode) }, 2000) }) }) </script> </html> ~~~ * 因此現在要解決的是防止連續點擊,思路 1. **addEventListener** 使用 **once** 參數限制點擊次數 ~~~ const list = document.querySelector('ul'); const buttons = list.querySelectorAll('button'); buttons.forEach((button) => { button.addEventListener('click', (evt) => { const target = evt.target; target.parentNode.className = 'completed'; setTimeout(() => { list.removeChild(target.parentNode); }, 2000); }, {once: true}); }); ~~~ 2. **removeEventListener** 觸發事件后將事件移除 這樣就不能點擊 ~~~ const list = document.querySelector('ul'); const buttons = list.querySelectorAll('button'); buttons.forEach((button) => { button.addEventListener('click', function f(evt) { const target = evt.target; target.parentNode.className = 'completed'; setTimeout(() => { list.removeChild(target.parentNode); }, 2000); target.removeEventListener('click', f); }); }); ~~~ 3. **disabled** 屬性禁止點擊 ~~~ const list = document.querySelector('ul'); const buttons = list.querySelectorAll('button'); buttons.forEach((button) => { button.addEventListener('click', (evt) => { const target = evt.target; target.parentNode.className = 'completed'; setTimeout(() => { list.removeChild(target.parentNode); }, 2000); target.disabled = true; }); }); ~~~ >[danger] ##### 通過函數編程思想解決 1. 先將只執行**一次**這個事進行抽象成一個函數,這個函數是負責用來修飾只需要將我們傳遞函數進行包裝后返回 2. 下面例子中把這個返回函數稱作是fn的**修飾函數**,而把**once**稱為函數的**裝飾器**,其中**replacer** 函數用來做一些第二次調用時異常處理提示 ~~~ // 封裝一個once 函數 function once(fn, replacer = null) { return (...args) => { if (fn) { const res = fn.apply(this, args) fn = null return res } if (replacer) { return replacer.apply(this, args) } } } // 使用 const list = document.querySelector('ul'); const buttons = list.querySelectorAll('button'); buttons.forEach((button) => { button.addEventListener('click', once((evt) => { const target = evt.target; target.parentNode.className = 'completed'; setTimeout(() => { list.removeChild(target.parentNode); }, 2000); })); }); ~~~ * 第二次執行時候拋出異常 ~~~ const obj = { init: once(() => { console.log('Initializer has been called.'); }, () => { throw new Error('This method should be called only once.'); }), } obj.init(); obj.init(); ~~~ >[danger] ##### 函數攔截器 1. 有時候我們需要對函數做一些改造,但是這類改造如果是在函數里面進行破壞性改造,可以采用類似思想做**裝飾器**。在函數執行前后將函數進行包裝 ![](https://img.kancloud.cn/ae/12/ae1214dccc1529534b506c7317908b69_691x329.png) ~~~ function intercept(fn, {beforeCall = null, afterCall = null}) { return function (...args) { if(!beforeCall || beforeCall.call(this, args) !== false) { // 如果beforeCall返回false,不執行后續函數 const ret = fn.apply(this, args); if(afterCall) return afterCall.call(this, ret); return ret; } }; } ~~~ * 使用前后加運行時間 ~~~ function sum(...list) { return list.reduce((a, b) => a + b); } sum = intercept(sum, { beforeCall(args) { console.log(`The argument is ${args}`); console.time('sum'); // 監控性能 }, afterCall(ret) { console.log(`The resulte is ${ret}`); console.timeEnd('sum'); } }); sum(1, 2, 3, 4, 5); ~~~ * 調整參數位置 ~~~ const mySetTimeout = intercept(setTimeout, { beforeCall(args) { [args[0], args[1]] = [args[1], args[0]]; } }); mySetTimeout(1000, () => { console.log('done'); }); ~~~ * 我們可以校驗函數的參數類型 ~~~ const foo = intercept(foo, { beforeCall(args) { assert(typeof args[1] === 'string'); } }); ~~~ >[danger] ##### 類似解決思想 1. **節流**是讓事件處理函數隔一個指定毫秒再觸發 2. **防抖**則忽略中間的操作,只響應用戶最后一次操作
                  <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>

                              哎呀哎呀视频在线观看