深入理解ES6--3.函式

你聽___發表於2018-04-20

深入理解ES6--3.函式

主要知識點有:函式引數預設值、剩餘引數、擴充套件運算子、new.target屬性、塊級函式、箭頭函式以及尾呼叫優化

深入理解ES6--3.函式

1. 函式引數預設值

  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);
     })
    複製程式碼
  2. 函式引數預設值表示式

    除了直接使用具體值賦給函式引數預設值外,函式引數預設值還可以有表示式構成。

     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),在函式引數預設值表示式中,還未初始化賦值的引數值無法作為其他引數的預設值

  3. 函式引數預設值對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. 箭頭函式

箭頭函式提供了一種更加簡潔的函式書寫方式,並且與傳統函式有很多不同的地方。箭頭函式基本的語法為:引數 => 函式體

根據引數的個數以及函式體的行數有多種變形:

  1. 無引數時,可以使用圓括號()表示;當只有一個引數時可以省略圓括號();當有多個引數時可以使用圓括號包裹,並引數之間用逗號進行分隔;
  2. 當函式體有多行語句時,使用大括號{}包裹起來,就像寫正常的函式一樣;當只有一行語句時,並需要返回結果時,可以省去大括號{},結果會自動返回。
  3. 如果需要返回物件的話,需要使用圓括號()將物件包裹起來,為了防止物件字面量被認為是函式體語句。

箭頭函式的特性:

  1. 沒有this、super、arguments,new.target繫結:this、super、arguments以及內部函式的new.target的值由所在的最近的外部非箭頭函式來決定;

  2. 沒有arguments物件繫結,但是能夠訪問包含它的外部函式的arguments物件;

     let outer = function(arg){
     	return ()=>arguments[0];
     }
     let inner = outer(7);
     console.log(inner()) //7
    複製程式碼
  3. 不能使用new來呼叫:箭頭函式沒有[[Construct]]方法,因此不能被用為建構函式,使用new呼叫函式會丟擲錯誤;

  4. 沒有原型:沒有使用new,因此沒有prototype屬性;

  5. 不能修改this:不能通過call(),apply()以及bind()方法修改this;

  6. 不允許使用重複的具名引數:箭頭函式不允許擁有重複的具名引數,無論是否在嚴格模式下;而傳統函式只有在嚴格模式下才禁止使用重複的具名引數;

7. 尾呼叫優化

尾呼叫是指在一個函式內最後的語句呼叫了另外一個函式,這個函式會重新建立新的棧幀並置於呼叫棧之上,如果呼叫次數過多,會導致記憶體過大。當滿足以下條件時,執行引擎會針對尾呼叫進行優化,不再重新建立新的棧幀,而是會複用當前棧幀:

  1. 尾呼叫不能引用當前棧幀中的變數;

  2. 進行尾呼叫的函式在尾呼叫返回結果後不能做額外任何操作;

  3. 尾呼叫的結果作為當前函式的返回值;

     //尾遞迴優化
     'use strict'
     
     function doSomething(){
     	//滿足尾呼叫優化條件
     	return doElse();
     }	
     
     
     function doSomething(){
     	let tmp = doElse();
     	//尾呼叫函式結果沒有直接返回,因此不滿足
     	//尾呼叫優化條件
     	return tmp;
     }	
     
     
     function doSomething(){
     	//尾呼叫函式後有其他額外操作,結果沒有
     	//立即返回,因此不滿足尾呼叫優化條件
     	return 1+doElse();
     }
    複製程式碼

由於閉包會持有外部函式的變數,因此對閉包的尾呼叫優化很難處理,但是,在遞迴操作中,可以利用到尾呼叫優化,減少棧幀個數,降低記憶體。

相關文章