這節學習ES6中對函數新增的方法和屬性。html
1.新增函數的參數默認值app
參考S6系列第二篇:http://www.cnblogs.com/diweikang/p/8976854.html函數
2.新增了函數的rest參數學習
參考ES6系列第二篇:http://www.cnblogs.com/diweikang/p/8976854.htmlthis
3.length屬性spa
做用:獲取函數預期傳入的參數個數。prototype
指定默認值後,length屬性將返回沒有指定默認值參數的個數。rest
(function (a) {}).length // 1 (function (a = 5) {}).length // 0 (function (a, b, c = 5) {}).length // 2
注意:若是設置了默認值的參數不是尾參數,length屬性也再也不計入後面的參數。code
(function (a = 0, b, c) {}).length // 0 (function (a, b = 1, c) {}).length // 1
4.嚴格模式htm
嚴格模式是ES5中新增語法的,限制指定的代碼在更嚴格的模式下執行。一般在腳本開頭或函數頭部添加"use strict"表達式來聲明。
<1>ES5開始,函數內部能夠顯示聲明嚴格模式。
function doSomething(a, b) { 'use strict'; // ... }
ES2016中規定,只要函數中使用了參數默認值、解構賦值、或者擴展運算符,函數內部就不容許顯示聲明嚴格模式,不然報錯。
// 參數默認值 function doSomething(a, b = a) { 'use strict'; // code } // 解構賦值 const doSomething = function ({a, b}) { 'use strict'; // code }; // 擴展運算符 const doSomething = (...a) => { 'use strict'; // code }; const obj = { // 解構賦值 doSomething({a, b}) { 'use strict'; // code } };
規定緣由:函數內部聲明的嚴格模式,限制函數參數和函數體都必須是嚴格模式執行。只有執行函數體的時候才能知道函數是不是嚴格模式,可是函數時先執行函數參數,再執行函數體的。這就致使參數若是不遵照嚴格模式,函數體中又顯示聲明嚴格模式,函數進行就會報錯。
// 嚴格模式八進制使用0o前綴表示 function doSomething(value = 070) { 'use strict'; return value; }
上面函數執行就會報錯。
如何規避這種限制:
<1>、設定全局性的嚴格模式。
'use strict'; function doSomething(a, b = a) { // ... }
<2>、把函數包裝在一個無參數的當即執行函數裏面。
const doSomething = (function () { 'use strict'; return function(value = 42) { return value; }; }());
5.name屬性
ES6新增函數的name屬性,返回該函數的函數名。
<1>將一個匿名函數賦值給一個變量,ES5的name屬性會返回空字符創,ES6的name屬性會返回實際的函數名稱。
var f = function () {}; // ES5 f.name // "" // ES6 f.name // "f"
<2>將一個具名函數賦值給一個變量,ES5和ES6的name屬性都會返回這個具名函數的名稱。
const bar = function baz() {}; // ES5 bar.name // "baz" // ES6 bar.name // "baz"
<3>構造函數返回的函數實例,name屬性值爲anonymous。
(new Function).name // "anonymous"
<4>將bind返回的函數,name屬性值會加上bound前綴。
function foo() {}; foo.bind({}).name // "bound foo" (function(){}).bind({}).name // "bound "
6.箭頭函數
ES6容許使用"箭頭"(=>)定義函數。
<1>箭頭函數須要一個參數。
var f = v => v; // 等同於 var f = function (v) { return v; };
<2>箭頭函數不須要或者須要多個參數,使用括號將參數部分括起來。
var f = () => 5; // 等同於 var f = function () { return 5 }; var sum = (num1, num2) => num1 + num2; // 等同於 var sum = function(num1, num2) { return num1 + num2; };
<3>箭頭函數代碼塊多餘一條語句,就要使用大括號括起來,並使用return語句返回。
var sum = (num1, num2) => { return num1 + num2; }
<4>若是箭頭函數須要返回一個對象,對象外面須要小括號括起來,不然會被當成代碼塊返回。
// 報錯 let getTempItem = id => { id: id, name: "Temp" }; // 不報錯 let getTempItem = id => ({ id: id, name: "Temp" });
<5>若是箭頭函數只有一行語句,且不須要返回值,能夠採用下面的寫法。
let fn = () => void doesNotReturn();
<6>箭頭函數與變量解構結合使用。
const full = ({ first, last }) => first + ' ' + last; // 等同於 function full(person) { return person.first + ' ' + person.last; }
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]]
<8>箭頭函數中的this對象。
注意:箭頭函數中的this老是指向函數定義生效時所在的對象。
function foo() { setTimeout(() => { console.log('id:', this.id); }, 100); } var id = 21; foo.call({ id: 42 }); // id: 42
上面代碼中,setTimeout
的參數是一個箭頭函數,這個箭頭函數的定義生效是在foo
函數生成時,而它的真正執行要等到 100 毫秒後。若是是普通函數,執行時this
應該指向全局對象window
,這時應該輸出21
。箭頭函數致使this
老是指向函數定義生效時所在的對象(本例是{id: 42}
),因此輸出的是42
。
再看一個例子:
function Timer() { this.s1 = 0; this.s2 = 0; // 箭頭函數 setInterval(() => this.s1++, 1000); // 普通函數 setInterval(function () { this.s2++; }, 1000); } var timer = new Timer(); setTimeout(() => console.log('s1: ', timer.s1), 3100); setTimeout(() => console.log('s2: ', timer.s2), 3100); // s1: 3 // s2: 0
分析:箭頭函數中的this指向箭頭函數定義生效時所在的對象,第一個定時器中的this指向timer對象,第二個定時器指向調用它的對象(全局對象),3100ms後s1更新了3次,而s2並無更新,因此結果是3和0。
總結:箭頭函數沒有自身的this對象。
1.函數體中this對象,定義時所在的對象,不是函數調用時所在對象。
2.不能夠當構造函數,也就是不可使用new命令。
3.不可使用arguments對象,該對象在箭頭函數體內不存在。
<9>雙冒號運算符
ES6中提出使用雙冒號(::)函數綁定的運算符,替代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); }
雙冒號左邊爲空,右邊是一個對象的方法,表示將函數綁定到這個對象上。
var method = obj::obj.foo; // 等同於 var method = ::obj.foo; let log = ::console.log; // 等同於 var log = console.log.bind(console);
總結:
上面這些就是咱們在開發中,可能會用到的ES6中關於函數的擴展的屬性和方法,仍是須要多練習多理解。