前言:專案中也經常用到es6的箭頭函式,但是也沒怎麼去細看es6更新了哪些函式特性,畢竟es7, es8都出來了。今天細看了《深入瞭解ES6》這本書的第三章,函式這一節,特此記錄一下es6更新了哪些函式的新特性。

1.函式形參的預設值。

   e5及之前,設定預設引數值均在函式內部去判斷是否傳了該引數,未傳值便賦予預設值,說實話我現在還在用這種思維寫函式,看來要改一改了,不然真的沒點進步了。

舉例:

function makeRequest(url,timeout,callback){

timeout=timeout||2000; //未傳值是undefined,這種寫法不安全,傳入0也是false 設為預設值

callback=callback||function(){};

//doSomething

}

//安全寫法,

function makeRequest(url,timeout,callback){

timeout=(typeof timeout!=="undefined")?timeout:2000; //雖安全但仍需額外程式碼來執行

callback=(typeof callback!=="undefined")?callback:function(){};

//doSomething

}

而ES6中的預設引數值:若未為引數傳值或傳入undefined,則為其提供預設值

舉例:

function makeReques(url,timeout=2000,callback=function(){}){

//doSomething

}

預設引數的特點:

(1)預設引數對arguments物件的影響

        es5非嚴格模式下,命名引數的變化會同步更新到arguments物件中。嚴格模式下將不會導致arguments改變

function mixArgs(first,second){//非嚴格模式
console.log(first===arguments[0]);
console.log(second===arguments[1]);
first="c",second="d";
console.log(first===arguments[0]);
console.log(second===arguments[1]);
}
mixArgs("a","b");
true
true
true
true
//嚴格模式下
function mixArgs(first,second){
"use strict"
console.log(first===arguments[0]);
console.log(second===arguments[1]);
first="c",second="d";
console.log(first===arguments[0]);
console.log(second===arguments[1]);
}
mixArgs("a","b")
true
true
false
false

在es6中:無論是否顯示定義了嚴格模式,arguments物件都將與es5嚴格模式下保持一致,預設引數值的存在將使arguments物件與命名引數分離。

(2)預設引數表示式

//非原始值傳參:

let value=5;
function getValue(){
return value++;
}
function add(fiirst,second=getValue()){
return first+second;
}
console.log(add(1,1));//2
console.log(add(1));//6
console.log(add(7));//6 每呼叫一次 未傳第二各引數的add將改變value的值。

正因預設引數是在函式呼叫時求值,可使用先定義的引數作為預設值,反之不可,預設引數的臨時死區。

(3)預設引數的臨時死區

函式引數有自己的作用域和臨時死區,其與函式體的作用域是各自獨立的,就是說引數的預設值不可訪問函式體內宣告的變數。

2.不定引數

在命名引數前加三個點(...)就表明這是一個引數,該參是一個數組,包含著自他之後的所有引數,通過陣列名即可逐一訪問各個引數;

function pick(object,...keys){
let result=Object.create(null);
for(let i=0,len=keys.length;i<len;i++){
result[keys[i]]=object[keys[i]];
}
return result;
}
let as={title:"es6",name:'Nicks',years:2012};
pick(as,...["name","years"]);//{name: "Nicks", years: 2012}

ES5中無命名引數

javascripts提供arguments物件來檢查函式的所有引數,因此不必定義每個要用的引數。實際使用有些笨重,不如es6不定引數

舉例:

function pick(object){
    let result=Object.create(null);
    //從第二個引數開始
    for(let i=1,len=arguments.length;i<len;i++){
        result[arguments[i]]=object[arguments[i]];
    }
    return results;
}
let as={title:"es6",name:'Nicks',years:2012};
pick(as,"name","years");//{name: "Nicks", years: 2012}

不定引數的使用限制:

① 每個函式最多隻能宣告一個不定參,必須在所有引數的末尾

②不定參不能用於物件字面量setter之中

③無論是否是用不定引數arguments物件總是包含所有傳入函式的引數。

注:另外還有其他特性:增強Function建構函式、展開運算子、name屬性,明確多重用途,(this),元屬性new.target、塊級函式,在此不細細說明

3、箭頭函式

(1)與傳統函式不同之處:

①沒有this,super,arguments和new.target繫結,箭頭函式中的這些值由外圍最近一層非箭頭函式決定。

②不能通過new關鍵字呼叫。它沒有[[Construct]],所以不能用作建構函式。如用會報錯

③沒有原型(prototype)

④不可以改變this的繫結,函式內部的this值不可被改變,在函式的生命週期內始終保持一致。

⑤不支援arguments物件。所以只能通過命名引數和不定引數兩種形式訪問函式引數。

⑥不支援重複的命名函式。

(2)箭頭函式語法:

    let 函式名=(引數1,引數2,...)=>{ };

   當只有一個引數時,可直接寫引數名。箭頭後也可不跟{},直接跟表示式或要返回的值,物件字面量要用()括住。

   辨識方法:typeof instanceof

(3)建立立即執行函式表示式:

        是javasscript函式比較流行的使用方式,可定義一個匿名函式並立即呼叫,自始至終不儲存對該函式的引用。(想建立一個與其他程式隔離的作用域時,該模式比較方便)。

//es5
let person =function(name){
    return {
        getName:function(){
            return name;
        }
    };
}("Nicholas");
console.log(person.getName());//"Nicholas"

//es6:
let person =((name)=>{
    return {
        getName:function(){
            return name;
        }
    };
})("Nicholas");
consol.log(person.getName());//"Nicholas"

(3)ES6尾呼叫優化(尾呼叫系統的引擎優化)

         尾呼叫指的是函式作為另個函式的最後一句被呼叫:

function doSomething(){
    return doSomethingElse();//尾呼叫
}

暫時也不太明白 ,書上是這麼說:尾呼叫優化可幫函式保持一個更小的呼叫棧,從而減少記憶體的使用,避免棧溢位錯誤,當程式滿足優化條件時,引擎會自動對其進行優化。

//遞迴:
function factorial(n){
    if(n<=1){
        return 1;
    }else{

        //無法優化,必在返回後執行乘法操作。
        return n*factorial(n-1);
    }
}

//ES6引擎優化:

function factorial(n,p=1){
    if(n<=1){
        return 1*p;
    }else{
        let result=n*p;

        //優化後
        return factorial(n-1,result);
    }
}

暫時就瞭解這麼多,後續有新見解再多補充。