這篇文章主要介紹了函數的擴展,函數的擴展只要有三個方面:函數
1 參數的默認值優化
2 箭頭函數this
3 關於尾調用的優化prototype
能夠在直接定義函數的時候,定義好參數若是沒傳或者傳錯 undefined。rest
//解構的基本用法 //用法1: function log(x, y = 'World') { console.log(x, y); } log('Hello'); //Hello World log('Hello', 'China'); /* Hello China */ log('Hello', ''); /* Hello */ 參數的默認值只有在沒傳時纔會生效。 //用法2: function week({ x, y = 5 }) { console.log(x, y); } week({}); /* undefined 5 */ week({x: 1}); /* 1 5 */ week({x: 1, y: 2}); /* 1 2 */ week(); /* TypeError: Cannot read property 'x' of undefined */ //用法3: function week({x, y = 5} = {}) { console.log(x, y); } week(); /* undefined 5 */
解構和參數的默認值須要注意的點:code
參數的變量已經默認聲明,不能用let或const再次聲明對象
function week(x = 5) { let x = 1; const x = 2; } /* SyntaxError: Identifier 'x' has already been declared */
函數不能有同名參數,由於參數的變量已經默認聲明因此不能再次聲明遞歸
function week(x, x, y = 1) { /* ... */ } /* SyntaxError: Duplicate parameter name not allowed in this context */
參數默認值是惰性求值token
當咱們真正運算走這個函數的時候,它纔會去處理默認的參數作用域
let x = 99; function week(p = x + 1) { console.log(p); } week(); /* 100 */ x = 100; week(); /* 101 */
參數默認值通常用於尾部,好比一個函數
length屬性,也就是函數的name和let,返回沒有指定默認值的參數個數
(function (a) {}).length; //1 (function (a = 5) {}).length; //0 (function (a, b, c = 5) {}).length; //2 (function (a = 0, b, c) {}).length; //0 (function (a, b = 1, c) {}).length; //1 (function(...args) {}).length; //0
設置了參數的默認值,參數會造成一個單獨的做用域
var x = 1; function f(x, y = x) { console.log(y); } f(2); //2 let x = 1; function f(y = x) { let x = 2; console.log(y); } f(); //1
好比一個函數的argument咱們知道這是函數的參數,argument其實是官方不推薦的一種用法。
function add(...values) { let sum = 0; for (var val of values) { sum += val; } return sum; } add(2, 5, 3); /* 10 */ function sortNumbers() { return Array.prototype.slice.call(arguments).sort(); } const sortNumbers = (...numbers) => numbers.sort();
function week() {}week.name;// "week" * var f = function () {};f.name // ""// ES6f.name // "f"
箭頭函數主要的兩點是:第一點它的this指向是在它當時定義所在的做用域,第二個是它沒有一個做用域的提高。
// 單個參數 var f = v => v; var f = function (v) { return v; }; // 多個參數 var sum = (num1, num2) => num1 + num2; var sum = function(num1, num2) { return num1 + num2; }; // return,有兩種場景,箭頭函數裏面直接寫return或者不寫的話箭頭函數就會默認把這個結果當成一個return。 也就是說當咱們返回一個對象時,沒有return語句的時候咱們須要再對象外面再包一個括號 var sum = (num1, num2) => { return num1 + num2; } // 1 返回對象 let getTempItem = id => { id: id, name: "Temp" }; // 2 Unexpected token : let getTempItem = id => ({ id: id, name: "Temp" }); // 結合解構 const full = ({ first, last }) => first + ' ' + last; // rest const numbers = (...nums) => nums; numbers(1, 2, 3, 4, 5); // [1,2,3,4,5]
箭頭函數使用的注意點:
函數體內的this對象指向定義時所在的對象而不是使用時所在的對象
function week() { setTimeout(() => { console.log('id:', this.id); }, 100); } //定義全局id(使用時的所在id) var id = 21; //調用,改變了this的值 week.call({ id: 42 }); // 42 function week() { return () => { return () => { return () => { console.log('id:', this.id); }; }; }; } //定義時的id=1,決定了它的做用域,所以下面的t1,t2,t3的輸出結果均爲1 var f = week.call({id: 1}); var t1 = f.call({id: 2})()(); var t2 = f().call({id: 3})(); var t3 = f()().call({id: 4}); // 1 // 對象不構成做用域 const cat = { lives: 9, jumps: () => { this.lives--; } }
不能夠看成構造函數,由於定義的時候是全局的
不可使用argument對象,這是一個規定,須要使用rest來代替
不可使用yield命令
通常用於嚴格模式,也就是說在嚴格模式下面,ES6作了一個尾調用的優化;可是在非嚴格模式下雖然也可使用尾調用,可是沒有優化。
尾調用基本概念:最後一步是調用另外一個函數,不適用於外部變量時只保留內層函數的調用幀(外部的變量不該該保存在return這個函數裏面,也就是返回的return並不使用這個做用域)。
function f(x){ return g(x); }
function factorial(n) { if (n === 1) return 1; return n * factorial(n - 1); } factorial(5); // 尾遞歸 function factorial(n, total) { if (n === 1) return total; return factorial(n - 1, n * total); } factorial(5, 1)
func( 'week', 'month', );