ES6語法(二) 函式

Godfrey1995發表於2019-03-10

ES6帶來最重要的變化之一就是函式的許多新特性,廢話不多說,我們直接從最重要的變化開始說起。

箭頭函式

ES6這次變化中最令人興奮的就是引入了箭頭(arrow)函式,js的開發者們已經等了太久了,之前的使用中,總是會被各種bind搞得暈頭轉向。現在有了箭頭函式,這些煩惱將不復存在。

基本語法

(params)=>{doSomething}

上面的形式使比較完整的。分為了函式引數、箭頭、函式體幾個部分。

若無函式引數,可以使用下面的形式:
=>{doSomething}

若是函式體只有一句的話,甚至可以省略包含函式體的大括號。

=> return a;

箭頭函式的this值:

在ES6之前,我們要是使用回撥函式傳參就要繫結函式的物件,否則會出錯。例:

    //如果繫結,函式將沒有執行環境
    document.getElementsByName('button').onClick(this.callBack.bind(this));

    function callBack(){ do somthing }
複製程式碼

而現在有了箭頭函式,那這一切將變得輕而易舉。


    document.getElementsByName('button'.onClick(()=>{
        do something...
    }));

複製程式碼

這是因為箭頭函式的this值直接繫結了外部函式的this值,並且這個this值是無法被改變的,雖然你可以使用箭頭函式呼叫call、apply、bind方法,但是他們依然無法改變函式的this繫結。這也是箭頭函式最重要的特性之一,不需要我們頻繁的手動繫結函式的執行物件了。

箭頭函式的引數。

首先要說的一點是箭頭函式沒有arguments物件。但是可以訪問外部函式的arguments物件。舉個例子

    function createArrowFunction(){
        return ()=> arguments[0];
    }
    
    let test = createArrowFunction(1,2,3,4,5);
    
    console.log(test);          // 1

複製程式碼

其實也很好理解,既然箭頭函式的this直接繫結了外部函式的this,那他就應該可以訪問到外部函式的arguments物件。

箭頭函式的引數同樣支援傳遞預設引數(詳細的會在後面講)。我們先來看看如何使用。

    let sum = (param1 = 1, param2 = 1)=>{
        console.log(param1 + param2);
    }
    
    sum();                      // 2
複製程式碼
箭頭函式的應用

我們上面也看到了一些箭頭函式的特性,首先我們來總結一下箭頭函式的特點。

  • 語法簡潔
  • 使用方便,無需設定this繫結,支援預設引數等特性

上面的特點導致了我們與陣列搭配在一起使用會相得益彰。

    let arr = [1,2,3,4,5];
    arr.forEach((element)=>{
        console.log(element);
    });
    // 1
    // 2
    // 3
    // 4
    // 5

複製程式碼

可以說箭頭函式是ES6中函式部分變化最大的改變。下面我們將瞭解一下ES6中函式的其他變化。

函式的預設引數(函式形參的預設值)

在ES6之前我們無法給函式形參新增預設值,但是我們會用另外的形式去模擬這種行為。

    function Person(name,age,sex){
        this.name = name;
        this.age = age || 18;
        this.sex = sex || female;
    }
    
    // name: Nero, age:20, sex:female
    new Person("Nero",20,female); 
    // name:Geodfrey,age:18,sex:female
    new Person("Grodfrey");
複製程式碼

在上面的例子中我們如果給函式的某個引數傳遞引數,那麼將使用傳遞的引數,否則將使用 “||”後面的內容,這樣就模擬了函式的預設引數。 上面的做法是一種很安全的做法,並且大多數JavaScript庫與開發者們都採用這種方式,但是ES6依然新增進來了新的方式,為的是我們更加方便的使用這種基礎操作。

基礎語法
    function Person(name,age = 20,sex = female){
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    
    // name:"Grodfrey", age:20, sex:female
    new Person("Grodfrey");

複製程式碼

其實很簡單,就是才定義形參時加一個 “=”,後面跟上內容,簡簡單單的。還有一個比較重要的事情是,預設引數並不是只支援傳遞原始值,也可以傳遞非原始值。例如函式表示式。這個傳遞什麼型別的原始值取決於你的實際情況。

還有一個比較重要的特點就是,如果你主動傳入undefined,函式也會呼叫預設值。

預設引數的臨時死區

函式的預設引數也有臨時死區,其實很容易理解,就是擁有預設值的引數不能在定義之前使用。我們來看個例子就好了。

    function sun(param1 = param2,param2 = 1){
            return param1 + param2;
    }
    
    sum(1,2);         // 2
    sum(undefined,1); //丟擲錯誤
複製程式碼

如果像下面的用法一樣就會報錯,簡單的來說就是在第一個引數要使用預設值(第二個引數)初始化時,但是第二個引數卻還沒有被初始化,這就產生了錯誤。

元屬性(new.target)

在ES6中為函式新增了元屬性,其實這個屬性就是為了讓我們區分函式的呼叫方式,如果使用new操作符呼叫函式時,元屬性就會被賦值為new操作法的目標物件。如果是通過其他方式呼叫的,那這個屬性的值就為undefined。

    function Person(name){
        if(new.target !== "undefined"){
            this.name = name;
        }else{
            console.log("請使用new操作符");
        }
    }
    
    let person = new Person("nero");
    Person.call(person,"Grodfery");     //請使用new操作符
複製程式碼

這樣的化我們就可以明確劃分函式的作用了。一些建構函式可以防止被其他型別的物件呼叫,產生一些錯誤。

new.target屬性只能在函式內部使用,如果在函式外部使用,將會丟擲錯誤。

塊級函式

在ES6中引入了塊級函式,這次是官方引入的,雖然之前有一些瀏覽器也都是實現了塊級函式,但是各不相同,這次ES6規定了塊級函式的語法。

塊級函式的語法很簡單,其實你完全可以當作一個let定義的變數來使用,唯一的一個區別就是:塊級函式會進行變數提升。

    if(true){
        
        console.log(typeOf doSomething);    // Function
        
        function doSomething(){}
        
    }
    
    console.log(typeof doSomething);        // undefined
複製程式碼

當塊級函式一旦離開相應的程式碼塊,那麼這個函式將被刪除。

不定引數與展開運算子

不定引數是執行你傳入數量不定的引數進入函式,在函式中會被整合成陣列。 而展開運算子與之相反,是將一個陣列打散,一個一個的傳入陣列。

不定引數的基本用法
    function Person(name,age,sex,...others){
        this.name = name;
        this.age = age;
        this.sex = sex;
        
        for(let i = 0;i<others.length;i++){
            console.log(others[i]);
        }
    }
複製程式碼

我們可以在傳入固定引數之後傳入任意多個引數。,都會被儲存在函式內部的不定引數同名的陣列中。

不定引數的限制

不定引數有兩個需要注意的地方

  1. 不定引數只能定義在函式引數列表的末尾。
    //這種使用方式是有錯誤的。
    // Uncaught SyntaxError: Rest parameter must be last formal parameter
    function doSomething(param1,...objs,param2){}
複製程式碼
  1. 不定引數不能用於物件字面量setter中。
    //這種操作也是不允許的,
    let obj = {
        set name(..key){}
    }
複製程式碼
不定引數與arguments物件

不定引數中的值也會在arguments中,也就是說,即使不實用不定引數,繼續使用原來的arguments物件也是完全沒問題的。

展開運算子的基本用法

展開運算子的用法就比較簡單了。

    let value = [1,2,3,4,5,6,7,8,9];
    
    console.log(Math.max(...value));
複製程式碼

展開運算子極大的方便了我們,我們不需要再寫一個迴圈或者通過其他方式將一個陣列的變數傳遞到函式中去,只需要在陣列前面使用 “...”符號,那麼就會將他們打散傳遞給函式。

這次探討的是ES6中有關函式的變動,有些內容我省略掉了,例如name屬性,我只列舉了一些我覺得會比較常用的。這都是基於我在工作中的認識,如果您有一些更好的想法或者是本篇文章某處錯誤,你都可以在下面留言給我!!!

相關文章