ES6函數新增內容介紹

前言

學習函數新增內容,需要先了解ES6的變量解構賦值。

本文大量引用阮一峰老師的ES6手冊。

為函數的參數設置默認值

function Point(x = 0, y = 0) {
  this.x = x;
  this.y = y;
}

const p = new Point();
console.log(p);

注意事項:

  1. 函數內部不允許給參數重復聲明,比如用var、let、const聲明。但可以重復賦值。
  2. 參數默認值不是傳值的,而是每次都重新計算默認值表達式的值,即時從前計算過,也當做沒計算過。也就是說,參數默認值是惰性求值的。

參數默認值跟解構賦值配合使用

首先你要懂ES6變量解構賦值

下面是利用對象的解構賦值,函數聲明的參數模式,必須與傳入值的模式匹配:

function foo({x, y = 5}) {
  console.log(x, y);
}

foo({}) // undefined 5 雖然是空對象,但是模式是匹配的
foo({x: 1}) // 1 5
foo({x: 1, y: 2}) // 1 2
foo() // TypeError: Cannot read property 'x' of undefined 傳入undefined,模式不匹配,所以報錯

如果想要什么參數都不傳,也依然不報錯,怎么做?依然是利用解構賦值,下面代碼中,{x, y = 5} = {}表示如果整個參數不存在,就默認為空對象,然后再計算x和y各是多少,x因為沒有對應值,當然是undefined,y雖然也沒有對應值,但是有默認值,所以y是5。

function foo({x, y = 5} = {}) {
  console.log(x, y);
}

foo() // undefined 5

對比下面兩段代碼,它們的結果是一樣的。區別在哪?

寫法一:

  1. 沒有傳參,所以用默認參數,也就是空對象。
  2. x和y先去空對象尋找對應值,找不到,所以用自己的默認值。

寫法二:

  1. 沒有傳參,所以用默認參數{ x: 0, y: 0 }
  2. x和y去{ x: 0, y: 0 }尋找對應值,找到了對應值,所以直接用對應值。

區別就是在哪一步設默認。所以,在任意一步設默認都可以,只要是合法的js代碼。

// 寫法一
function m1({x = 0, y = 0} = {}) {
  return [x, y];
}
console.log(m1());

// 寫法二
function m2({x, y} = { x: 0, y: 0 }) {
  return [x, y];
}
console.log(m2());

參數默認值應該放到參數隊列最后面

這么做的目的是可以省略若干傳參。如果參數默認值排在前面,沒有默認值的參數反而在后面,那么傳參的寫法就會很不科學,比如:

function f(x, y = 5, z) {
  return [x, y, z];
}

怎么傳參?

f() // [undefined, 5, undefined]
f(1) // [1, 5, undefined]
f(1, ,2) // 報錯 這種最簡練的寫法是錯誤的
f(1, undefined, 2) // [1, 5, 2] 這種寫法雖然正確,但是把undefined傳進去代碼很丑

所以,如果參數有默認值就應該放到參數隊列最后面。

參數默認值有特殊作用域

var x = 1;

 // 2作為值傳給x,由于y = x是完全獨立的作用域,所以y的值是參數x的值,也是2
function f(x, y = x) {
  console.log(y); // 打印2
}

f(2) // 2
let x = 1;

 // 沒有傳入值,所以y取默認值,y=x形成獨立作用域,所以y是x的值,x指向外層的1,也就是y是1。
function f(y = x) {
  let x = 2; // 這個x不影響y的值
  console.log(y); // 打印1
}

f() // 1

還有更復雜的情況,這里不多介紹了,更復雜的情況可能只會出現在面試題里,而實踐中,請讓自己的代碼條理清晰,這樣對自己,對別人,都有好處。

參數默認值的一個應用

先定義一個通用函數,不干別的,只負責報錯:

function throwIfMissing() {
  throw new Error('Missing parameter');
}

然后,其他函數里面如果有不允許省略的參數,就賦值為這個函數:

function throwIfMissing() {
  throw new Error('Missing parameter');
}

function foo(a, b, c = throwIfMissing()) {

}

foo(1,2); // Uncaught Error: Missing parameter

rest參數

學習變量解構賦值的時候,我們就遇到了rest變量,也就是:

let [a, b, ...c] = [1,2,3,4,5,6,7];
console.log(c); // [3,4,5,6,7]

參數也有這種寫法,表示剩余的傳參,有多少我全包了。

function add(...values) {
  let sum = 0;

  for (var val of values) { // values 是一個數組,包含所有傳入的參數
    sum += val;
  }

  return sum;
}

add(2, 5, 3) // 10

所以,到現在,傳參真的可以為所欲為,根本不再是ES5時代的參數必須一對一:

  1. 你有一系列參數,我用比如...args就可以打包。
  2. 如果你傳入一個數組,我用解構賦值就可以打散。

箭頭函數

箭頭函數是ES6對函數寫法的最大修改,改到人們一開始都不認識。

var f = v => x;
// 等價于
var f = function(v) {
  return x;
};

代碼塊部分多于一條語句,就要使用大括號將它們括起來,并且使用return語句返回。

var sum = (num1, num2) => num1 + num2;
// 等價于
var sum = function(num1, num2) {
  return num1 + num2;
};

由于大括號是被默認解釋為代碼塊,所以如果箭頭函數直接返回一個對象,必須在對象外面加上括號,否則會報錯。

// 報錯
let getTempItem = id => { id: id, name: "Temp" };

// 不報錯
let getTempItem = id => ({ id: id, name: "Temp" });

箭頭函數可以與變量解構結合使用:

const full = ({ first, last }) => first + ' ' + last;
// 等價于
function full({ first, last }) {
  return first + ' ' + last;
}

// 使用函數的時候就full({first: 4, last: 8});就可以了

箭頭函數寫法的優勢:

  1. 簡練。定義一個判斷是偶數的函數如下,因為這個函數就是參數跟運算,所以箭頭函數很簡練:
const isEven = n => n % 2 == 0;
  1. 簡化回調函數。ES5時代,為了清洗的寫回調函數,往往要折行寫代碼,現在就簡化了。
// 正常函數寫法
[1,2,3].map(function (x) {
  return x * x;
});

// 箭頭函數寫法
[1,2,3].map(x => x * x);


// 正常函數寫法
var result = values.sort(function (a, b) {
  return a - b;
});

// 箭頭函數寫法
var result = values.sort((a, b) => a - b);

注意,箭頭函數不是永遠等價于常規寫法。區別如下:

  1. 常規寫法中,this對象的指向是可變的,但是在箭頭函數中,它是固定的。這也是ES6為了降低js學習難度所做的改變。常規寫法中,函數體內的this對象,不一定是定義時所在的對象,而是使用時所在的對象。但是,箭頭寫法中,函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象。

  2. 不可以當作構造函數,也就是說,不可以使用new命令,否則會拋出一個錯誤。

  3. 不可以使用arguments對象,該對象在函數體內根本不存在。如果要用,可以用 rest 參數代替。

  4. 不可以使用yield命令,因此箭頭函數不能用作 Generator 函數。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 函數參數的默認值 基本用法 在ES6之前,不能直接為函數的參數指定默認值,只能采用變通的方法。 上面代碼檢查函數l...
    呼呼哥閱讀 3,442評論 0 1
  • 1.函數參數的默認值 (1).基本用法 在ES6之前,不能直接為函數的參數指定默認值,只能采用變通的方法。
    趙然228閱讀 704評論 0 0
  • [TOC] 參考阮一峰的ECMAScript 6 入門參考深入淺出ES6 let和const let和const都...
    郭子web閱讀 1,808評論 0 1
  • 第 2 章:函數基礎 函數式編程不是僅僅用 function 這個關鍵詞來編程。如果真這么簡單,那我這本書可以到此...
    iKcamp閱讀 951評論 0 7
  • 函數和對象 1、函數 1.1 函數概述 函數對于任何一門語言來說都是核心的概念。通過函數可以封裝任意多條語句,而且...
    道無虛閱讀 4,630評論 0 5