ES6 函式擴充套件
函式預設值
ES6 與ES5 的區別
在ES6之前,不能直接為函式的指定預設值
ES5預設值方法
//方法一
function log(x, y) {
y = y || 'value';
console.log(x, y);
}
function log(x, y) {
if (typeof y === 'undefined') {
y = 'value';
}
console.log(x, y);
}
es6
function log(x, y = 'value') {
console.log(x, y);
}
與解構賦值預設值結合使用
解構賦值自行領會
function fn1({x=0,y=1}={}){
console.log(x,y)
};
function fn2({x,y}={x:0,y:1}){
console.log(x,y)
}
fn1();
//0 1
fn2();
//0 1
fn1({x:2,y:2})
//2 2
fn2({x:2,y:2})
//2 2
fn1({x:2})
//2 1
fn2({x:2})
//2 undefined
fn1({})
//0 1
fn2({})
//undefined undefined
fn1({z:1})
//0 1
fn2({z:1})
//undefined undefined
預設引數省略
通常情況下,定義了預設值的引數,應該是函式的尾引數。因為這樣比較容易看出來,到底省略了哪些引數。如果非尾部的引數設定預設值,實際上這個引數是沒法省略的。
function f(x = 1, y) {
return [x, y];
}
f()
// [1, undefined]
f(2)
// [2, undefined])
f(, 1)
// 報錯不執行
f(undefined, 1)
//[1,1]
ps 預設引數尾部省略原則
函式的length 屬性
(function(x,y){}).length
//2
(function(x,y=4){}).length
//1
(function(x=1,y=4){}).length
//0
作用域
var x = 1;
function foo(x, y = function() { x = 2; }) {
var x = 3;
y();
console.log(x);
}
foo() // 3
x // 1
var x = 1;
function foo(x, y = function() { x = 2; }) {
x = 3;
y();
console.log(x);
}
foo() // 2
x // 1
y = function() { x = 2; }中的x 指向第一個引數x
foo函式中 對x 是否 var 決定 foo函式的x 指向是 引數x;或是獨立的不屬於一個作用域的x
rest引數
ES6 引入 rest 引數(形式為“…變數名”),用以獲取函式的多餘引數,這樣就不需要使用arguments物件了
function val(...values){
for(var val of values){
console.log(val)
}
}
val(1,4,6,7,8,9)
//1
//4
//6
//7
//8
//9
ps : rest引數之後不能再有其他引數了
擴充套件運算子
擴充套件運算子(spread)是三個點(…)。它好比 rest 引數的逆運算,將一個數組轉為用逗號分隔的引數序列。
嚴格模式
從ES5開始,函式內部可以設定為嚴格模式。
function doSomething(a, b) {
'use strict';
// code
}
《ECMAScript 2016標準》做了一點修改,規定只要函式引數使用了預設值、解構賦值、或者擴充套件運算子,那麼函式內部就不能顯式設定為嚴格模式,否則會報錯。
箭頭函式
var f = x => x;
上面的箭頭函式等同於:
var f = function(x) {
return x;
};
不需要引數或需要多個引數情況
如果箭頭函式的程式碼塊部分多於一條語句,就要使用大括號將它們括起來,並且使用return語句返回。
由於大括號被解釋為程式碼塊,所以如果箭頭函式直接返回一個物件,必須在物件外面加上括號。
var f = () => 5;
var fn=(x,y)=>x+y
var fn1=(x,y)=>{return x+y}
var fn2=(x,y)=>({name:x,age:y})
var full = ({ first, last }) => first + ' ' + last;
// 等同於 person={first:'wewe',last:'ffd'}格式
function full(person) {
return person.first + ' ' + person.last;
}
使用注意點
箭頭函式有幾個使用注意點。
函式體內的this物件,就是定義時所在的物件,而不是使用時所在的物件。
不可以當作建構函式,也就是說,不可以使用new命令,否則會丟擲一個錯誤。
不可以使用arguments物件,該物件在函式體內不存在。如果要用,可以用Rest引數代替。
不可以使用yield命令,因此箭頭函式不能用作Generator函式。
上面四點中,第一點尤其值得注意。this物件的指向是可變的,但是在箭頭函式中,它是固定的。
箭頭函式ES5
// ES6
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
// ES5
function foo() {
var _this = this;
setTimeout(function () {
console.log('id:', _this.id);
}, 100);
}
this 繫結
箭頭函式可以繫結this物件,大大減少了顯式繫結this物件的寫法
ES7提出了“函式繫結”(function bind)運算子,用來取代call、apply、bind呼叫。雖然該語法還是ES7的一個提案,但是Babel轉碼器已經支援。
foo::bar;
// 等同於
bar.bind(foo);
foo::bar(...arguments);
// 等同於
bar.apply(foo, arguments);
如果雙冒號左邊為空,右邊是一個物件的方法,則等於將該方法繫結在該物件上面。
尾遞迴
在ES6中,只要使用尾遞迴,就不會發生棧溢位,相對節省記憶體。
ES6的尾呼叫優化只在嚴格模式下開啟,正常模式是無效的。
這是因為在正常模式下,函式內部有兩個變數,可以跟蹤函式的呼叫棧。
func.arguments:返回呼叫時函式的引數。
func.caller:返回呼叫當前函式的那個函式。
嚴格模式下
尾呼叫即可
非嚴格模式下
function tco(f) {
var value;
var active = false;
var accumulated = [];
return function accumulator() {
accumulated.push(arguments);
if (!active) {
active = true;
while (accumulated.length) {
value = f.apply(this, accumulated.shift());
}
active = false;
return value;
}
};
}
var sum = tco(function(x, y) {
if (y > 0) {
return sum(x + 1, y - 1)
}
else {
return x
}
});
sum(1, 100000)