es6 函數 學習總結

 ==========================函數參數默認值=======================
        es6使用參數的默認值, 在書寫的時候,直接給形參賦值,賦的值就是默認值
        例如:
         function add( a = 1, b = 2 , c){
             retrun a + b + c;
          }

          add(undefined,undefined, 2 )  // 5
          add(1,2,3) // 6

          默認參數不一定只可以是字面量, 可以是對象, 任何有意義的賦值都可以, 函數, 對象, 數組,正則等

          參數默認值對arguements的影響?
          嚴格模式下 "use strict" , 形參與arguements是脫離的
          非嚴格格式下, 形參與arguements是統一的
          只要給函數加上參數默認值, 該函數就會自動變成嚴格模式下, 就是形參與arguements脫離

          留意暫時性死區?
          形參和ES6中的let或者const聲明一樣, 具有作用域,並且根據形參的聲明順序,存在暫時性死區
          例如:
          function test(a, b= a){
              console.log(a, b)
          }
          
          第一次調用: test(1, 2) // 1 2
          第二次調用: test(1)  // 1 1

          但是如果test方法是如下的寫法:
          function test(a = b, b){
              console.log(a, b)
          }

          第一次調用 test(undefined, 2) // 報錯, 報暫時性死區的錯誤

          得出結果: 在函數裏面,定義變量儘量不要和形參同名


          =====================es6剩餘參數========================
          以前使用的是arguements,
          arguements的缺陷:
          1. 如果和形參配合使用, 容易導致混亂, 嚴格模式形參與arguements還相脫離
          2. 從語義上使用arguements獲取參數,由於參數缺少,無法從函數定義上無法理解函數的意圖

          es6的剩餘參數: 專門用於收集末尾的所有參數,將其放置到一個形參數組中
          使用方法: 形參前面加上三點
          function(...形參名){

          }
          細節:
           1. 一個函數,僅能出現一個剩餘參數
           2. 一個函數,如果有剩餘參數, 剩餘參數必須是最後一個參數


          =====================展開運算符===============================
           如下面的例子:
            <script>
                /**
                * @description: 
                * @param :  arg 剩餘參數
                * @return:  函數的和
                */
                function sum(...arg) {
                    let res = 0;
                    arg.forEach(item => {
                        res += item;
                    })
                    return res;
                }
                /**
                * @description:  獲取指定長度的數組
                * @param : length 長度
                * @return:  結果
                */
                function getRandomNumbers(length) {
                    let res = [];
                    for (let i = 0; i < length; i++) {
                        res.push(Math.random());
                    }
                    return res;
                }
            </script>

             let arr =  getRandomNumbers(10);
             sum(arr)  // 此時傳入的是一個數組, 但是剩餘參數哪裏打印 arg會得到一個二維數組
                         所以數組需要展開
              
              es6 提供對數組展開: ...需要展開的數組
              es7 提供對對象展開: ...需要展開的對象  
              
              所以上面的例子就可以使用 sum(...arr); 就可以求和了。

              使用 ... 還可以實現下面的操作,
              1. 一個數組克隆到另一個數組(淺克隆) 如: const arr = [1,2,3,4]; const arr2 = [...arr1];
              2. 一個對象克隆到另一個對象(淺克隆), 如 const obj1 = {name: 1, age: 2}; const obj2 = {...obj1, sex: male}

                /**
                * @description: 柯里化 用戶固定某個函數前面的參數,得到一個新的函數,新函數調用時候,接受剩餘參數
                * @param : 
                * @return: 
                */
                function curry(fn, ...args) {
                    return function (...subArgs) {
                        const allArgs = [...args, ...subArgs];
                        // 參數夠了
                        if (allArgs.length >= fn.length) {
                            return fn(...allArgs);
                        } else {
                            // 參數不夠,繼續固定
                            curry(fn, ...allArgs);
                        }
                    }
                }
           
         =========================es6函數的雙用途=====================
         函數可以當作普通函數, 也可以當作構造函數
         例如:
            function Person(firstName, lastName){
                // 嚴格模式需要判斷是否使用new 來判斷

                // 過去的判斷方式
                if(!(this instance of Person)){
                    throw new Errow(" 該函數沒有使用new 來調用")
                }

                //es6判斷, 完美判斷
                if(new.target === undefined){
                    throw new Errow(" 該函數沒有使用new 來調用")
                }
                this.firstName = firstName;
                this.lastName = lastName;
                this.fullName = `${firstName}${lastName}`
            }

            const p1 = new Person("成", "都");
            console.log(p1) // 要給構造函數對象

            const p2 = Person("成", "都");
            console.log(p2) //undefined

            過去的那種方法會存在弊端, 如果有人強制傳遞this是person,但是又不是new如下:
            const p3 = Person.call(new Person("成""都"),"成","都");
            console.log(p3)  // undefined


            現在es6提供一個特殊的api, 可以使用該API在函數的內部,判斷函數是否使用了new來調用
            語法:
            new.target 
            // 該表達式得到的是:如果沒有使用new來調用函數,返回的是undefined,
             如果使用new來調用,則得到的是new關鍵字後面的函數本身


         ===============es6箭頭函數===================================
         解決this的指向問題

         this指向: 
          1. 通過對象調用函數,this指向那個調用者
          2. 直接調用函數, this指向的是window
          3. 如果通過new調用函數, this指向新創建的對象
          4. 如果通過 apply, call, bind調用函數, this指向指定的數據
          5. 如果是DOM時間函數, this指向事件源
         
         存在的問題 :
            例如: 
            const obj = {
                count: 0,
                start: function(){
                    // 這裏的this指向的是調用者, 就是obj
                    setInterval(function(){
                        // 這裏的這個this 指向的是全局的window
                        this.count++;
                    },1000)
                },
                regEvent: function(){
                    windwo.onclick = function(){
                        // this 指向的是事件源
                    }
                }
            }

            obj.start();
            obj.regEvent();

         箭頭函數解決this的指向問題:

         語法:
         箭頭函數是一個函數表達式,理論上任何使用函數表達式的場景,都可以使用箭頭函數   
         (參數1,參數2...=> {}
         如果參數只有一個,可以省略小括號
         參數 => {}
        如果箭頭函數裏面只有一條語句並且還是返回的,那麼可以省略大括號和return
        例如: const isOdd = num => num%2 !== 0; 
            // 返回值是一個對象,需要用小括號括起來
            const sum = (a,b) => ({
                a: a,
                b: b,
                sum: a + b;
            })

         細節:
          1. 箭頭函數的的函數體中的this,取決於箭頭函數定義的位置的this指向,而於調用無關
          2. 箭頭函數, 不存在this, arguments, new.target, 如果使用了,那就是使用的是外層函數的
          3. 箭頭函數沒有原型, 箭頭函數佔用的內存空間小,因爲沒有原型
          4. 箭頭函數不能當作構造函數, 沒有原型

         應用場景:
         1. 臨時性使用的函數,並不會調用它, 比如:
              1. 事件處理函數
              2. 異步處理函數, setTimeOut等
              3. 其他臨時性函數
         2. 爲了綁定外層this的函數
         3. 數組方法中的回調函數
         4. 在不影響其他代碼的情況下,保持代碼的簡潔      
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章