ES6 系列四:函數的擴展

"Code tailor",爲前端開發者提供技術相關資訊以及系列基礎文章,微信關注「小和山的菜鳥們」公衆號,及時獲取最新文章。

前言

在開始學習以前,咱們想要告訴您的是,本文章是對阮一峯《ECMAScript6 入門》一書中 "函數的擴展" 章節的總結,若是您已掌握下面知識事項,則可跳過此環節直接進入題目練習javascript

  • 函數參數的默認值
  • 做用域
  • rest 參數
  • 箭頭函數

若是您對某些部分有些遺忘,👇🏻 已經爲您準備好了!前端

學習連接

函數的擴展學習java

彙總總結

函數參數的默認值

爲函數的參數指定默認值
// ES5寫法
function log(x, y) {
  y = y || 'World'
  console.log(x, y)
}

log('Hello') // Hello World

// ES6寫法
function log(x, y = 'World') {
  console.log(x, y)
}

log('Hello') // Hello World

優勢:es6

  • 閱讀代碼的人,能夠馬上意識到哪些參數是能夠省略的,不用查看函數體或文檔
  • 有利於未來的代碼優化,即便將來的版本在對外接口中,完全拿掉這個參數,也不會致使之前的代碼沒法運行

注意:數組

  • 參數變量是默認聲明的,因此不能用 letconst 再次聲明
function foo(x = 5) {
  let x = 1 // error
  const x = 2 // error
}
  • 使用參數默認值時,函數不能有同名參數
// 不報錯
function foo(x, x, y) {
  // ...
}

// 報錯
function foo(x, x, y = 1) {
  // ...
}
  • 參數默認值不是傳值的,而是每次都從新計算默認值表達式的值。也就是說,參數默認值是惰性求值的
let x = 99
function foo(p = x + 1) {
  console.log(p)
}

foo() // 100

x = 100
foo() // 101

做用域

一旦設置了參數的默認值,函數進行聲明初始化時,參數會造成一個單獨的做用域(context)。等到初始化結束,這個做用域就會消失。這種語法行爲,在不設置參數默認值時,是不會出現的。
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

rest 參數

ES6 引入 rest 參數(形式爲...變量名),用於獲取函數的多餘參數,這樣就不須要使用 arguments 對象了。 rest 參數搭配的變量是一個數組,該變量將多餘的參數放入數組中。
function add(...values) {
  let sum = 0

  for (var val of values) {
    sum += val
  }

  return sum
}

add(2, 5, 3) // 10

//上面代碼的add函數是一個求和函數,利用 rest 參數,能夠向該函數
//傳入任意數目的參數。
注意, rest 參數以後不能再有其餘參數(即只能是最後一個參數),不然會報錯。

箭頭函數

ES6 容許使用「箭頭」( =>)定義函數。
var f = (v) => v

// 等同於
var f = function (v) {
  return v
}

若是箭頭函數不須要參數或須要多個參數,就使用一個圓括號表明參數部分。微信

var f = () => 5
// 等同於
var f = function () {
  return 5
}

var sum = (num1, num2) => num1 + num2
// 等同於
var sum = function (num1, num2) {
  return num1 + num2
}

若是箭頭函數的代碼塊部分多於一條語句,就要使用大括號將它們括起來,而且使用 return 語句返回。函數

var sum = (num1, num2) => {
  return num1 + num2
}

箭頭函數有幾個使用注意點:學習

  • 函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象。
  • 不能夠看成構造函數,也就是說,不可使用new命令,不然會拋出一個錯誤。
  • 不可使用arguments對象,該對象在函數體內不存在。若是要用,能夠用 rest 參數代替。
  • 不可使用yield命令,所以箭頭函數不能用做 Generator 函數。

上面四點中,第一點尤爲值得注意。this對象的指向是可變的,可是在箭頭函數中,它是固定的。優化

題目自測

一:如下代碼輸出什麼this

var x = 1
function foo(x, y = () => (x = 5)) {
  x = 9
  y()
  console.log(x)
}

foo()

二:如下代碼輸出什麼

const shape = {
  radius: 10,
  diameter() {
    return this.radius * 2
  },
  perimeter: () => 2 * Math.PI * this.radius,
}

shape.diameter()
shape.perimeter()
  • A: 20 and 62.83185307179586
  • B: 20 and NaN
  • C: 20 and 63
  • D: NaN and 63

三:解釋下述代碼(含義、運行結果以及做用)。

f1 = (x) => (y) => (z) => x * y * z

題目解析

1、

Answer:5

首先須要看明白函數foofunction foo(x, y = () => x = 5),重點在於第二個y = () => x = 5,意思爲須要給與foo函數一個函數,若是沒有,那麼 y 表明的就是

;() => {
  x = 5
}

這一個函數,這裏調用 foo,並無給與第二個函數,那麼執行的時候,y()實際上就是將 x 賦值爲 5,所以打印出來爲 5


2、

Answer:B

首先須要瞭解,在箭頭函數中,this的指向和在普通函數中不一樣,箭頭函數中this指向在定義的時候就肯定好了。在diameter函數中,經過this.radius訪問的就是shape中的radius,爲 10

可是,在perimeter函數中,後面經過this.radius訪問的radius並非shape中的radius,在外層尋找找不到,所以返回NaN。所以答案爲20 and NaN


3、

首先,這樣子使用箭頭函數邏輯不是很清楚,將其轉換爲普通函數:

function f1(x) {
  return function f2(y) {
    return function f3(z) {
      return x * y * z
    }
  }
}

含義:將三個數相乘

運行結果:f1(x)(y)(z)===x*y*z

最外層,f1 是一個帶一個形參的函數,返回值是一個帶一個形參的函數 f2,f1(x)(y)(z)->f2(y)(z),f2 返回值是一個帶一個形參的函數 f3,f2(y)(z)->f3(z),由於返回的函數是在 f1f2 中定義的,根據做用域鏈,能夠取到 xy 的值,因此f3的返回值爲x*y*z,最後 f1(x)(y)(z)===x*y*z

ES 6 系列的 函數的擴展,咱們到這裏結束啦,謝謝各位對做者的支持!大家的關注和點贊,將會是咱們前進的最強動力!謝謝你們!

相關文章
相關標籤/搜索