ES6&函數擴展

ES6函數的擴展

1.函數默認值

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

示例
function print(x,y='world'){
console.log(x,y);
}
print('hello'); //hello world
在ES5中則需要判斷傳參是否存在,再進行默認值賦值

參數變量是默認聲明的,使用let和const再次進行聲明會報錯,var聲明則不會,因為let定義不允許在相同作用域內重復聲明一個變量。

2.函數的length屬性

定義:函數的length屬性將返回沒有指定默認值的參數個數

示例
//在ES5中獲取函數的參數個數需要函數return
function count(x,y){
return arguments.length;
}
//ES6中新增函數length屬性
(function (x,y){}).length; //2
function count(x,y = "world"){
}
console.log(count.length); //1,指定默認值不算進去

3.函數的name屬性

定義:獲取函數的名稱

var hello = function(){};
hello.name; //hello
//Function構造函數返回的示例name為anonymous
(new Function()).name; //anonymous

4.rest參數

定義:rest參數的寫法為(...變量名),用于獲取函數多余的變量,可替代arguments,rest參數中的變量是一個數組,arguments是類數組對象需要使用Array.from()方法轉換成真正數組。

示例
function add(...numbers){
let count = 0;
for (let i of numbers){
count += i;
}
return count;
}
//或者使用numbers.forEach(x => count += x);
rest參數變量是一個數組,數組特有的方法都可以使用。
rest參數后不能再有其他的參數,rest參數必須為最后一個參數,使用函數屬性length獲取參數個數,rest參數不計入。
示例
function add(a,...numbers,c){
} //error
(function(a,b,...numbers){}).length; //2,rest參數不算

5.擴展運算符...

定義: 擴展運算符的寫法為(...),將一個數組轉為用逗號分隔的參數序列

示例
console.log(1,...[2,3,4,5],6); //1,2,3,4,5,6

使用擴展運算符替代apply()方法

//ES5
Math.max.apply(null,[4,6,0]); //Math.max不能接受數組為參數
Math.max(4,6,0);
//ES6
Math.max(...[4,6,0]);

使用擴展運算符合并數組

//ES5
var arr1 = [1,2,3];
var arr2 = [4,5,6,];
var arr = arr1.concat(arr2);
//ES6
var array1 = Array.of(1,2,3);
var array2 = Array.of(4,5,6);
var array = [...array1,...array2];

使用擴展運算符可將具有Iterator接口的數據結構轉換成真正的數組(ES6數組擴展篇章也有提及)

[...'hello']; //將字符串轉化成數組
var NodeList = [...document.querySelectorAll('p')];//類似數組對象
var someSet = new Set([4,5,6]);
var array = [...someSet.keys()]; //Set數據結構
var someMap = new Map([['name','lijaha'],['age',20]]);
var array = [...someMap.keys()]; //Map數據結構

6.箭頭函數

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

示例
var hello = x => x;
//如果箭頭函數不需要參數或者需要多個參數就用()圓括號代表參數部分
var hello = () => 1; //return 1
var hello = (x,y) => x+y;
//如果箭頭函數的代碼塊語句多于一句,需要使用大括號{}括起來
var hello = (x,y) => {return x+y};
//如果箭頭函數返回的是對象,則需要在大括號外加上小括號({})
var hello = id => ({id: id,name: 'world'});

箭頭函數體內的this對象是定義時所在的對象,而不是使用時所在的對象,稱為箭頭函數的this指向固定化。因為箭頭函數內部是沒有自己的this(不能作為構造函數,也不能使用apply、call、bind等方法改變this指向),所以它的this是外層代碼塊的this。

箭頭函數內部沒有arguments對象,需使用rest參數代替

var hello = (...numbers) => {console.log(...numbers)};

尾調用優化

定義:指某個函數在最后一步調用另一個函數

function hello(){

return hi();

} //尾調用的結尾一定是return xx();

函數調用會在內存中形成一個“調用幀”,保存調用位置和內部變量等信息。如果函數A中調用用了函數B,則會在函數A調用幀的上方形成一個B的調用幀,函數B執行完畢后,函數A中的調用幀B才會結束。如果函數B內調用了函數C,就會形成一個C地調用幀,所有的調用幀就會形成一個‘調用棧’。

//尾調用是函數的最后一步操作,所以不需要保留外層函數的調用幀,外層函數的調用位置和內部變量都不會用到。
function hello(){
let m = 1;
let n = 2;
return g(m+n);
}
//等同于
function hello(){
return g(3);
}
//等同于
g(3);
//上面代碼中,如果函數g不是尾調用則函數hello需要保留內部變量m、n以及調用位置等信息,由于函數hello調用函數g后,hello函數就結束了,則可以刪除hello()的調用幀,只保留g()的調用幀。

這就叫做‘尾調用優化’,即只保留內層函數的調用幀,如果所有的函數都是尾調用,則可以做到每次執行時調用幀只有一項。

//只有不再用到外層函數的內部變量,內層函數的調用幀才能取代外層函數的調用幀,實現尾調用優化。
function hello(a){
let b = 1;
function hi(a){
return a + b; //使用了hello函數的內部變量b
}
return hi(a);
}

尾遞歸

函數自己調用自己則叫遞歸,函數在尾部調用自己則稱為尾遞歸

//使用遞歸實現階乘,遞歸過程會比較耗費內存,因為保存大量的調用幀,容易發生棧溢出。
function factorial(n){
if(n == 1) return 1;
return nfactorial(n-1);
}
//使用尾遞歸
function factorial(n,total=1){ //使用默認值
if(n == 1) return total;
return factorial(n-1,n
total);
} //每次只保存一個調用記錄
一般的遞歸的復雜度為O(n),使用尾遞歸的復雜度為O(1)

需要開啟嚴格模式,尾調用優化才會生效,一旦使用尾調用優化,函數的內部對象arguments和caller都會失效,因為整個外層函數調用幀會被刪除掉,這兩個對象也就不存在了。嚴格模式下,這兩個對象也是不可用的。

function hello(){
"use strict";
hello.arguments; //error
hello.caller; //error
}

本文章參考阮一峰《ES6 標準入門》

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1.函數參數的默認值 (1).基本用法 在ES6之前,不能直接為函數的參數指定默認值,只能采用變通的方法。
    趙然228閱讀 708評論 0 0
  • 函數參數的默認值 基本用法 在ES6之前,不能直接為函數的參數指定默認值,只能采用變通的方法。 上面代碼檢查函數l...
    呼呼哥閱讀 3,476評論 0 1
  • 函數新增特性 函數默認值,rest參數,擴展運算符,箭頭函數,this綁定,尾調用 函數參數的默認值 rest參數...
    bjhu電net閱讀 217評論 0 0
  • // 參數默認值 在有默認值的參數后面不能有沒有默認值的參數,比如(x,y='world',c) 不允許 { ...
    super靜_jingjing閱讀 207評論 0 1
  • 想送你回家的人,東南西北都順路。愿陪你吃飯的人,酸甜苦辣都愛吃。想見你的人,24小時都有空。
    南望先生的日記本閱讀 271評論 0 0