主要知識點有:函式引數預設值、剩餘引數、擴充套件運算子、new.target屬性、塊級函式、箭頭函式以及尾呼叫優化
1. 函式引數預設值
-
函式引數預設值
let defaultFunc = function(url,tomeout=2000,callback={}){}; //使用預設的timeout和callback defaultFunc('/url'); //使用預設的callback defaultFunc('/url',100); //使用指定的timeout和callback defaultFunc('/url',100,function(body){ doSomething(body); }) 複製程式碼
函式引數預設值的指定順序可以隨意
//需要指定預設引數的可選引數timeout,排在callback let defaultFunc = function(url,tomeout=2000,callback){}; 複製程式碼
只有在未傳遞引數,或者引數為undefined時,才會使用預設引數,null值被認為是有效的
//null被認為是有效的,不會使用timeout的預設值 defaultFunc('/url',null,function(body){ doSomething(body); }) 複製程式碼
-
函式引數預設值表示式
除了直接使用具體值賦給函式引數預設值外,函式引數預設值還可以有表示式構成。
function getValue(){return 5}; function test(a,b=getValue()){ return a+b; } //呼叫getValue console.log(test(1)); //6 //不使用b的預設值s console.log(test(1,2)); //3 複製程式碼
可以使用前面的引數,來作為後面引數的預設值。前面的引數預設值不能引用後面的引數值
function add(a,b=1){return a+b}; console.log(add(1,1)); //2 function addition(a=b,b){return a+b}; console.log(addition(undefined,1)); //Uncaught ReferenceError: b is not defined 複製程式碼
函式引數預設值存在暫時性死區(TDZ),在函式引數預設值表示式中,還未初始化賦值的引數值無法作為其他引數的預設值
-
函式引數預設值對arguments物件的影響
-
ES5中,在非嚴格模式下,arguments物件能夠反映出具名引數的變化,當具名引數值更新的時候,arguments物件中相應的元素值也會更新。在嚴格模式下不能反映出具名引數的變化
function testArgs(a,b){ console.log(a===arguments[0]); //true console.log(b===arguments[1]); //true a='c'; b='d'; console.log(a===arguments[0]); //true console.log(b===arguments[1]); //true } testArgs('a','b'); 複製程式碼
-
在ES6中,引數預設值與arguments物件分離,即被賦予引數預設值的引數無法從arguments物件中獲取。另外,無論是非嚴格模式下,還是在嚴格模式下,具名引數的更改都不會在arguments物件中更新。
-
2. 剩餘引數
ES6中,當引數個數無法確定時,可以使用剩餘引數(rest parameter)來表示,剩餘引數就相當於一個容器,呼叫函式時傳入幾個引數值,這個容器就裝載幾個引數值。剩餘引數能夠將多個獨立的引數合併到一個陣列中去,剩餘參數列示為...keys
,有三個點加上一個具名引數識別符號組成。
function rp(...keys){console.log(keys.length)}
rp(1,2); //2
複製程式碼
具名引數只能放在引數組最後面,並且只能有且僅有一個剩餘引數。剩餘引數不能作為物件字面量的setter屬性
let person ={
set name(...names); //Setter function argument must not be a rest parameter
}
複製程式碼
在Function構造器中能夠將函式體以字串的形式作為函式的引數,並且支援引數預設值以及剩餘引數
var add = new Function("first","second","return first+second");
console.log(add(1,1)); //2
複製程式碼
3. 擴充套件運算子
擴充套件運算子能夠將陣列分離,將分割後單獨的引數值傳遞給函式,能夠替代apply()方法的使用。
console.log(Math.min(0,...[1,2,3,4])); //0
複製程式碼
4. new.target屬性
能夠使用new.target
屬性來判斷函式是否利用new
來進行呼叫
function target(){
if(new.target!=='undefined'){
console.log('通過new來呼叫');
}else{
console.log('不是通過new來呼叫');
}
}
複製程式碼
5. 塊級函式
在程式碼塊中能夠宣告函式,函式也被稱之為塊級函式,在嚴格模式下,塊級函式會提升到當前所處程式碼塊的頂部,在整個程式碼塊中都能夠被訪問,在程式碼塊外的地方就不能被訪問。而在非嚴格模式下,塊級函式會被提升到全域性作用域。
6. 箭頭函式
箭頭函式提供了一種更加簡潔的函式書寫方式,並且與傳統函式有很多不同的地方。箭頭函式基本的語法為:引數 => 函式體
。
根據引數的個數以及函式體的行數有多種變形:
- 無引數時,可以使用圓括號()表示;當只有一個引數時可以省略圓括號();當有多個引數時可以使用圓括號包裹,並引數之間用逗號進行分隔;
- 當函式體有多行語句時,使用大括號{}包裹起來,就像寫正常的函式一樣;當只有一行語句時,並需要返回結果時,可以省去大括號{},結果會自動返回。
- 如果需要返回物件的話,需要使用圓括號()將物件包裹起來,為了防止物件字面量被認為是函式體語句。
箭頭函式的特性:
-
沒有this、super、arguments,new.target繫結:this、super、arguments以及內部函式的new.target的值由所在的最近的外部非箭頭函式來決定;
-
沒有arguments物件繫結,但是能夠訪問包含它的外部函式的arguments物件;
let outer = function(arg){ return ()=>arguments[0]; } let inner = outer(7); console.log(inner()) //7 複製程式碼
-
不能使用new來呼叫:箭頭函式沒有[[Construct]]方法,因此不能被用為建構函式,使用new呼叫函式會丟擲錯誤;
-
沒有原型:沒有使用new,因此沒有prototype屬性;
-
不能修改this:不能通過call(),apply()以及bind()方法修改this;
-
不允許使用重複的具名引數:箭頭函式不允許擁有重複的具名引數,無論是否在嚴格模式下;而傳統函式只有在嚴格模式下才禁止使用重複的具名引數;
7. 尾呼叫優化
尾呼叫是指在一個函式內最後的語句呼叫了另外一個函式,這個函式會重新建立新的棧幀並置於呼叫棧之上,如果呼叫次數過多,會導致記憶體過大。當滿足以下條件時,執行引擎會針對尾呼叫進行優化,不再重新建立新的棧幀,而是會複用當前棧幀:
-
尾呼叫不能引用當前棧幀中的變數;
-
進行尾呼叫的函式在尾呼叫返回結果後不能做額外任何操作;
-
尾呼叫的結果作為當前函式的返回值;
//尾遞迴優化 'use strict' function doSomething(){ //滿足尾呼叫優化條件 return doElse(); } function doSomething(){ let tmp = doElse(); //尾呼叫函式結果沒有直接返回,因此不滿足 //尾呼叫優化條件 return tmp; } function doSomething(){ //尾呼叫函式後有其他額外操作,結果沒有 //立即返回,因此不滿足尾呼叫優化條件 return 1+doElse(); } 複製程式碼
由於閉包會持有外部函式的變數,因此對閉包的尾呼叫優化很難處理,但是,在遞迴操作中,可以利用到尾呼叫優化,減少棧幀個數,降低記憶體。