ES6規定只要函數參數使用了默認值、解構賦值、或者擴展運算符,編程
那麼函數內部就不能顯式設定爲嚴格模式,不然會報錯數組
1. 參數的默認值app
ES6 容許爲函數的參數設置默認值,即直接寫在參數定義的後面函數式編程
函數不能有同名參數函數
let a = 1;
每次調用函數foo
,都會從新計算x + 1
,而不是默認p
等於 100優化
let x = 99; function foo(p = x + 1) { console.log(p); } foo(); // 100
x = 100; foo(); // 101
function log(x, y = 'World') { console.log(x, y); } log('Hello'); // Hello World
log('Hello', 'China'); // Hello China
log('Hello', ''); // Hello
function Point(x = 0, y = 0) { this.x = x; this.y = y; } const p = new Point(); console.log(p); // { x: 0, y: 0 }
返回沒有指定默認值的參數個數this
3. 參數初始化做用域spa
一旦設置了參數的默認值,函數進行參數聲明初始化時,參數會造成一個單獨的做用域(context)。prototype
等到初始化結束,這個做用域就會消失。rest
這種語法行爲,在不設置參數默認值時,是不會出現的。
參數初始化,實際上,執行的是 let 關鍵字聲明
4. rest 多餘 實參數組
...args x, ...args
...數組名 實參, 多餘參數數組
實參列表,是一個真數組
用於獲取函數的多餘參數
push
方法的例子function push(arr, ...items) { items.forEach(function(item) { arr.push(item); console.log(item); }); }; var arr = []; push(arr, 1, 2, 3)
length
屬性,不包括 rest 參數,由於 rest 參數表示 多餘的實參列表console.log((function(a) {}).length); // 1
console.log((function(...a) {}).length); // 0
console.log((function(a, ...b) {}).length); // 1
5. 箭頭函數 const func = () => {};
簡化原來的 const func = function(){};
箭頭函數 沒有本身的顯式原型屬性,即 func.prototype = undefined;
箭頭函數 不能做爲構造函數使用,即不能 new 調用
箭頭函數 的 this 指向最近的包裹函數的 this 一致,若是沒有函數包裹,則 this 指向 window
箭頭函數 可讓 this
指向固定化,這種特性頗有利於封裝回調函數
實際緣由是箭頭函數根本沒有本身的 this,致使內部的 this 就是外層代碼塊的 this。
正是由於它沒有 this,因此也就不能用做構造函數
於箭頭函數沒有本身的 this,因此固然也就不能用call()、apply()、bind()這些方法去改變this的指向
其實箭頭函數也沒有 arguments
、super
、new.target
箭頭函數的函數體內 不能夠使用 arguments 對象,該對象在函數體內不存在。若是要用,能夠用 rest 參數代替
不能夠使用 yield 命令,所以箭頭函數不能用做 Generator 函數
var handler = { id: '123456', init: function() { document.addEventListener('click', event => this.doSomething(event.type), false); }, doSomething: function(type) { console.log('Handling ' + type + ' for ' + this.id); } };
const func = (x) => {};
const func = x => {};
const func = x => { x += 1;};
const func = x => x+=1;
let getTempItem = id => ({ id: id, name: "Temp" });
// 正常函數寫法
[1,2,3].map(function (x) { return x * x; }); // 箭頭函數寫法
[1,2,3].map(x => x * x);
rest 參數 與 箭頭函數的結合使用
const numbers = (...nums) => nums; numbers(1, 2, 3, 4, 5); // [1,2,3,4,5]
const headAndTail = (head, ...tail) => [head, tail]; headAndTail(1, 2, 3, 4, 5); // [1,[2,3,4,5]]
定義函數的方法,且該方法內部包括 this
const cat = { lives: 9, jumps: () => { this.lives--; // this 指向 window ,因此結果確定是有問題的 }; };
須要動態this
的時候,也不該使用箭頭函數
var button = document.getElementById('press'); button.addEventListener('click', () => { this.classList.toggle('on'); });
6. 雙冒號運算符——函數綁定運算符——"對象::函數(參數列表)"
背景:
箭頭函數能夠綁定 this 對象,大大減小了顯式綁定 this 對象的寫法(call、apply、bind)。
可是,箭頭函數並不適用於全部場合,因此如今有一個提案,提出了「函數綁定」(function bind)運算符,
用來取代 call、apply、bind 調用箭頭函數能夠綁定 this 對象,大大減小了顯式綁定 this 對象的寫法(call、apply、bind)
foo::bar; // 等同於
bar.bind(foo); foo::bar(...arguments); // 等同於
bar.apply(foo, arguments); const hasOwnProperty = Object.prototype.hasOwnProperty; function hasOwn(obj, key) { return obj::hasOwnProperty(key); };
函數調用 會在內存造成一個「調用記錄」,又稱「調用幀」(call frame),保存調用位置和內部變量等信息。
若是在函數 A 的內部調用函數 B ,那麼在 A 的調用幀上方,還會造成一個 B 的調用幀。
等到 B 運行結束,將結果返回到 A,B 的調用幀纔會消失。若是函數 B 內部還調用函數 C,
那就還有一個 C 的調用幀,以此類推。全部的調用幀,就造成一個「調用棧」(call stack)
指某個函數的最後一步操做是調用另外一個函數
是函數式編程的一個重要概念
只在嚴格模式下開啓,正常模式是無效的
function f(x){ return g(x); };
// 狀況一
function f(x){ let y = g(x); return y; }; // 狀況二
function f(x){ return g(x) + 1; }; // 狀況三
function f(x){ g(x); };
即只保留內層函數的調用幀。若是全部函數都是尾調用,那麼徹底能夠作到每次執行時,調用幀只有一項,這將大大節省內存。
內層函數 若是用到了 外層函數 的變量
若是尾調用自身,就稱爲尾遞歸
遞歸很是耗費內存,由於須要同時保存成千上百個調用幀,很容易發生「棧溢出」錯誤(stack overflow)
尾遞歸的實現: 每每須要改寫 遞歸函數,確保最後一步只調用自身。
把全部用到的內部變量改寫成函數的參數。
採用 ES6 的函數默認值
函數式編程有一個概念,叫作柯里化(currying),意思是: 將多參數的函數轉換成單參數的形式。
function factorial(n, total) { if (n === 1){ return total; }; return factorial(n - 1, n * total); }; factorial(5, 1); // 120
function Fibonacci2 (n , ac1 = 1 , ac2 = 1) { if( n <= 1 ){ return ac2; }; return Fibonacci2 (n - 1, ac2, ac1 + ac2); } Fibonacci2(100); // 573147844013817200000
Fibonacci2(1000); // 7.0330367711422765e+208
Fibonacci2(10000); // Infinity
容許定義和調用時,尾部直接有一個逗號
函數參數與數組和對象的尾逗號規則,保持一致了
function clownsEverywhere(param1, param2, ) { /* ... */ } clownsEverywhere('foo', 'bar', );