深入理解ES6--3.函數

原創文章&經驗總結&從校招到A廠一路陽光一路滄桑

詳情請戳www.coderccc.com

主要知識點有:函數參數默認值、剩餘參數、擴展運算符、new.target屬性、塊級函數、箭頭函數以及尾調用優化

函數的知識點

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();
     }
    

由於閉包會持有外部函數的變量,因此對閉包的尾調用優化很難處理,但是,在遞歸操作中,可以利用到尾調用優化,減少棧幀個數,降低內存。

發佈了40 篇原創文章 · 獲贊 38 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章