ES 6 : 函數的擴展


1. 函數參數的默認值

[ 基本用法 ]

  在ES6之前,不能直接為函數的參數指定默認值,只能采用變通的方法。

   上面的代碼檢查函數log的參數y有沒有賦值,如果沒有,則指定默認值為world。這種寫法的缺點在於,如果參數y賦值了,但是對應的布爾值為false,則該賦值不起作用。就像以上代碼的最后一行,參數y等於空字符,結果被改為默認值。

  ES6允許為函數的參數設置默認值,即直接寫在參數定義的后面。

[ 與解構賦值默認值結合使用 ]

  參數默認值可以與解構賦值的默認值結合起來使用。

[ 參數默認值的位置 ]

  通常情況下,定義了默認值的參數應該是函數的尾參數。如果非尾部的參數設置默認值,實際上這個參數是無法省略的。

  

  有默認值的參數都不是尾參數。這時,無法只省略該參數而不省略其后的參數,除非顯式輸入undefined。如果傳入undefined,將觸發該參數等於默認值,null沒有這個結果。

[ 函數的length屬性 ]

  指定了默認值之后,函數的length屬性將返回沒有指定默認值的參數個數。

  length屬性的含義是,該函數預期傳入的參數個數。某個參數指定默認值之后,預期傳入的參數個數就不包括這個參數了。

[ 作用域 ]

  如果參數默認值是一個變量,則該變量所處的作用域與其他變量的作用域規則是一樣的,即先是當前函數的作用域,然后才是全局作用域。

  如果調用時函數作用域內部的變量x沒有生成,結果就會不一樣。

  函數調用時y的默認值變量x尚未在函數內部生成,所以x指向全局變量。

[ 應用 ]

  利用參數默認值,可以指定某一個參數不得省略,如果省略就拋出一個錯誤。

  以上代碼中的foo函數,如果調用的時候沒有參數,就會調用默認值throwIfMissing函數,從而拋出一個錯誤。

 2. rest參數

  ES6引入了rest參數(形式為"...變量名"),用於獲取函數的多余參數,這樣就不需要使用arguments對象了。rest參數搭配的變量是一個數組,該變量將多余的參數放入其中。

  以上代碼中的add函數是一個求和函數,利用rest參數可以向該函數傳入任意數目的參數。下面是rest參數代替arguments變量的例子。

  // arguments 變量的寫法

  // rest 變量的寫法

  注意:rest參數之后不能有其他參數,函數的length屬性不包括rest參數。

3. 擴展運算符

[ 含義

  擴展運算符是三個點(...)。它好比rest參數的逆運算,將一個數組轉為用逗號分隔的參數序列。

  擴展運算符與正常的函數參數可以結合使用。

function f(v,w,x,y,z){} var args = [0,1]; f(-1,...args,2,...[3]);

[ 替代數組的apply方法 ]

  由於擴展運算符可以展開數組,所以不再需要apply方法將數組轉為函數的參數了。下面是擴展運算符取代apply方法的一個實際的例子,應用Math.max方法簡化求數組最大元素的寫法:

// ES5的寫法
Math.max.apply(null,[14,3,77]) // ES6的寫法
Math.max(...[14,3,77])

[ 擴展運算符的應用 ]

- 合並數組

  擴展運算符提供了數組合並的新寫法。

- 與解構賦值結合

  擴展運算符可以與解構賦值結合起來用於生成數組。

  如果將擴展運算符用於數組賦值,只能放在參數的最后一位,不然會報錯。

- 函數的返回值

  JavaScript的函數只能返回一個值,如果需要返回多個值,只能返回數組或對象。擴展運算符提供了解決這個問題的一種變通方法。

var dateFields = readDateFields(database); var d = new Date(...dateFields);

  上面的代碼用於從數據庫中取出一行數據,通過擴展運算符直接將其傳入構造函數Date。

- 字符串

  擴展運算符還可以將字符串轉為真正的數組。

[ 類似數組的對象 ]

  任何類似數組的對象都可以用擴展運算符轉為真正的數組。

var nodeList = document.querySelectorAll("div"); var array = [...nodeList];

  上面的代碼中,querySelectorAll方法返回的是一個nodeList對象,擴展運算符可以將其轉為真正的數組。

[ Map 和 Set 結構,Generator 函數 ]

  擴展運算符內部調用的是數據結構的Iterator接口,因此只要具有Iterator接口的對象,都可以使用擴展運算符,比如Map結構。

[ name屬性

  函數的name屬性返回該函數的函數名。

  如果將一個匿名函數賦值給一個變量,ES5的name屬性會返回空字符串,而ES6的name屬性會返回實際的函數名。

  如果將一個具名函數賦值給一個變量,則ES5和ES6的name屬性都返回這個具名函數原本的名字。

5. 箭頭函數

[ 基本用法 ]

  ES6允許使用"箭頭"(=>)定義函數。

var f = v => v; // 上面的箭頭函數等同於
var a = function(v){ return v; };

  如果箭頭函數不需要參數或需要多個參數,就使用圓括號代表參數部分。

var f = () => 5; // 等同於
var f = function(){ return 5 }; var sum = (num1,num2) => num1 + num2; // 等同於
var sum = function(num1,num2){ return num1+num2; };

  如果箭頭函數的代碼塊部分多於一條語句,就要使用大括號將其括起來,並使用return語句返回。

var sum = (num1,num2) => { return num1 + num2 }

  由於大括號被解釋為代碼塊,所以如果箭頭函數直接返回一個對象,必須在對象外面加上括號。

var getTempItem = id => ({ id: id, name: "Temp" });

  箭頭函數可以與變量解構結合使用。

const full = ({ first, last }) => first + '' + last; // 等同於
function full(person){ return person.first + '' + person.name; }

  箭頭函數使得表達更加簡潔。

const isEven = n => n % 2 == 0;

  箭頭函數的一個用處是簡化回調函數。

// 正常函數的寫法
[1,2,3].map(function(x){ return x*x; }); // 箭頭函數的寫法
[1,2,3].map(x => x*x);

  箭頭函數還能與rest參數結合。

[ 使用注意點 ]

  箭頭函數有幾個使用注意點。

  ● 函數體內的this對象就是定義時所在的對象,而不是使用時所在的對象。

  ● 不可以當做構造函數。也就是說,不可以使用new命令,否則會拋出一個錯誤。

  ● 不可以使用arguments對象,該對象在函數體內不存在。如果要用,可以用rest參數代替。

  ● 不可以使用yield命令,因此箭頭函數不能用作Generator函數。

 6.函數綁定

  箭頭函數沒有自己的this,導致內部的this就是外層代碼塊的this。正因為它沒有this,所以也就不能用作構造函數。當然也不能使用call()、apply()、bind()這些方法去改變this的指向。

  函數綁定運算符是並排的雙冒號(::),雙冒號左邊是一個對象,右邊是一個函數。該運算符會自動將左邊的對象作為上下文環境綁定到右邊的函數上。

foo::bar // 等同於
bar.bind(foo) foo::bar(...arguments) // 等同於
bar.bind(foo,arguments)

  如果雙冒號左邊為空,右邊是一個對象的方法,則等於將該方法綁定在該對象上。

var method = obj::obj.foo // 等同於
var method = ::obj.foo

  由於雙冒號運算符返回的還是原對象,因此可以采用鏈式寫法。

import {map,takeWhild,forEach} from "iterlib"; getPlayers() ::map(x => x.character()) ::takeWhile(x => x.strength > 100); ::forEach(x => console.log(x));

7.尾調用優化

[ 尾調用概念 ]

  尾調用是函數式編程的一個重要概念,本身非常簡單,一句話就能說清楚,就是指某個函數的最后一步是調用另一個函數。

function f(x){ return g(x) }

  以下情況都不屬於尾調用:

// 情況一
function f(x){ let y = g(x); return y; } // 情況二
function f(x){ return g(x)+1; } // 情況三
function f(x){ g(X); }

  上面的代碼中,情況一是調用函數g之后還有賦值操作,所以不屬於尾調用,即使語義完全一樣;情況二也屬於調用后還有操作,即使寫在一行內;情況三等同於下面的代碼。

function f(x){ f(x); return undefined; }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM