ES6函數的改變不算太大,都是一些其餘語言早就有的功能,而Javascript一直比較欠缺的,好比函數參數默認值,任意參數的表示法,最大的變化應該是支持箭頭函數(其餘語言稱之爲LAMBDA表達式),一種對匿名函數的一種簡寫方式,如下來探討一下函數在ES6中的一些改變:
數組
1. 默認參數(default parameters) 2. 任意參數(rest parameters ...) 3. spread 操做符(...) 4. new.target 元屬性 5. 箭頭函數( => ) 6. 其餘一些改動(miscellaneous)
ES6以前一直是經過其餘方法來模擬默認參數的,例如邏輯或||符號,ES6版本真正意義上支持這種便利的寫法。app
// ES5模擬默認參數 function person(name, age) { name = name || "James"; age = age || "18"; console.log(name + " " + age); } // 通常狀況下這種寫法是沒問題的,當邏輯或前面的值爲falsy值,整個表達式返回後面的值 // 例如: person("Louis"); // ok person(); // ok person(undefined, 20); // ok person("baby", 0); // "baby 18" error, 0爲falsy值
上面能夠看出這種寫法是有必定問題的,各類JS庫給出了另外一種寫法函數
function person(name, age) { if (typeof name === "undefined") { name = name || "James"; } if (typeof age === "undefined") { age = age || "18"; } console.log(name + " " + age); } person(undefined, 0); // ok "James 0"
ES6寫法性能
function person(name = "James", age = 18) { console.log(name + " " + age); } // 1各類寫法 默認參數出如今中間 function getRequest(url, timeout = 2000, callback) { // do something } gerRequest("/foo", undefined, function() { }); // 2默認參數表達式 let value = 5; function getValue() { return value++; } function add(first, second = getValue()) { return first + second; } add(3); // 8 add(3); // 9 add(1, 1); // 2 // 3後面參數引用前面參數 function add(first, second = first) { return first + second; } add(2); // 4 add(3, 4); // 7
默認參數TDZ(暫時死區)狀況:優化
// 上面的第三種寫法,若寫成第一個參數引用第二個參數 function add(first = second, second) { return first + second; } add(1, 1); // ok 2 add(undefined, 4); // THROW AN ERROR 第二個參數未聲明就引用就會拋出錯誤 // 就至關於 let first = second; // error let second = 4;
ES6任意參數用 ...
表示,任意參數和arguments之間的差異
ES5使用arguments參數來實現對象屬性拷貝:ui
function pick(object) { var result = Object.create(null); // 建立一個對象 // 從第二個參數開始 for (var i = 1, len = arguments.length; i < len; i++) { result[arguments[i]] = object[arguments[i]]; } return result; } // arguments將object也計入,因此除開第一個參數要減1 var book = { title: "understanding ES6", author: "Nicholas C.Zakes", year: 2016 }; var o = pick(book, "author", "year"); o.author; // "Nicholas C.Zakes" o.year; // 2016
上面的pick函數看上去不夠直觀,由於除第一個參數外不知道要添加幾個參數,使用新語法this
function pick(object, ...keys) { var result = Object.create(null); // 建立一個對象 for (var i = 0, len = keys.length; i < len; i++) { result[keys[i]] = object[keys[i]]; } return result; } // keys將object不計入在其內 var book = { title: "understanding ES6", author: "Nicholas C.Zakes", year: 2016 }; var o = pick(book, "author", "year"); o.author; // "Nicholas C.Zakes" o.year; // 2016
使用rest parameters注意事項:
1.要將任意參數放到函數的最後,不能放在中間位置
2.不能用於對象字面量setter中url
function pick(object, ...keys, last) { //... } // 語法錯誤 let object = { set name(...value) { // do something } }; // 語法錯誤
spread操做符和rest parameters同樣,都使用 ...
表示,spread操做符容許咱們將數組中的參數一個一個傳入函數中
例如:prototype
// Math.max()函數, 通常能夠加入任意個參數 Math.max(12, 13, 14, 15); // 15 // 以數組的形式 var arr = [1, 2, 3, 4]; Math.max.apply(null, arr); // 4 // 使用 "..." Math.max(...arr); // 4 // 還能夠加入其它的一些參數 Math.max(...arr, 5, 10); // 10
將一個數組去重:調試
var arr = [1, 2, 2, 4, 4]; // 使用Set將重複的去掉,而後將set對象轉變爲數組 var mySet = new Set(arr); // mySet {1, 2, 4} // 方法1,使用Array.from轉變爲數組 // var arr = Array.from(mySet); // [1, 2, 4] // 方法2,使用spread操做符 var arr = [...arr]; // [1, 2, 4] // 方法3, 傳統forEach var arr2 = []; mySet.forEach(v => arr2.push(v));
函數內部有兩個方法 [[call]] 和 [[construct]] (箭頭函數沒有這個方法),當使用new 操做符時, 函數內部調用 [[construct]], 建立一個新實例,this指向這個實例; 不使用new 操做符時, 函數內部調用 [[call]]。
判斷一個函數是否使用new操做符,ES5的方法:
function Person(name) { if (this instanceof Person) { this.name = name; } else { throw new Error("You must use new operator"); } } var p = new Person("James"); // ok var p = Person("James"); // error // 可是能夠經過其餘方式繞過這種錯誤 var notPerson = Person.call(p, "Nicholas"); // works
ES6 經過new.target 來判斷是否使用new,元屬性 是指一個提供目標相關額外信息(好比new)的非對象屬性。
function Person(name) { if (typeof new.target !== "undefined") { this.name = name; } else { throw new Errow("You must use new operator"); } } var p = new Person("James"); // ok var notPerson = Person.call(p, "Louis"); // error
箭頭函數有如下幾個方面的特色:
1.箭頭函數語法
// 語法很簡單 let sum = (n1, n2) => n1 + n2; // 至關於 let sum = function(n1, n2) { return n1 + n2; }; let getTempItem = id => ({ id: id, name: "Temp" }); // 至關於 let getTempItem = function(id) { return { id: id, name: "Temp" }; };
2.沒有this綁定
let PageHandler = { id: "123456", init: function() { document.addEventListener("click", function(event) { this.doSomething(event.type); // error }, false); }, doSomething: function(type) { console.log("Handling " + type + " for " + this.id); } }; // init函數中的this.doSomething,this指向的是函數內部document對象, // 而不是PageHandler對象
使用箭頭函數改寫:
let PageHandler = { id: "123456", init: function() { document.addEventListener("click", event => this.doSomething(evnet.type) }, false); }, doSomething: function(type) { console.log("Handling " + type + " for " + this.id); } }; // 此處箭頭函數this指向包含它的函數,即init,init爲PageHandler的方法, // this指向PageHandler對象實例
3.不能使用new
var MyType = () => {}; var obj = new MyType(); // Error
4.沒有arguments對象
箭頭函數沒有arguments對象,可是能夠使用包含函數中的arguments對象
function createArrowFunctionReturningFirstArg() { // arguments 爲 createArrowFunctionReturningFirstArg中的對象 return () => arguments[0]; } var arrowFunction = createArrowFunctionReturningFirstArg(10); arrFunction(); // 10
其餘的一些變化:
總結
整體來講,這些改動都是爲編寫程序提供了極大的便利,不用再使用workaround來解決語法存在的問題,總體來說,更加符合語言的書寫習慣。