1. 程式人生 > >ES6 函式擴充套件

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;
};
  1. 不需要引數或需要多個引數情況

  2. 如果箭頭函式的程式碼塊部分多於一條語句,就要使用大括號將它們括起來,並且使用return語句返回。

  3. 由於大括號被解釋為程式碼塊,所以如果箭頭函式直接返回一個物件,必須在物件外面加上括號

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;
}

使用注意點

箭頭函式有幾個使用注意點。

  1. 函式體內的this物件,就是定義時所在的物件,而不是使用時所在的物件。

  2. 不可以當作建構函式,也就是說,不可以使用new命令,否則會丟擲一個錯誤。

  3. 不可以使用arguments物件,該物件在函式體內不存在。如果要用,可以用Rest引數代替。

  4. 不可以使用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)