es6 快速入門 系列 —— 函數

其餘章節請看:javascript

es6 快速入門 系列html

函數

函數是全部編程語言的重要組成部分,es6以前函數語法一直沒什麼變化,遺留了許多問題,javaScript開發者多年來不斷抱怨,es6終於決定大力度更新函數特性,函數變得比之前更易於使用了。java

試圖解決的問題

默認參數

es5中模擬默認參數,一般這麼實現:es6

function demo1(v1, v2, v3){
    v2 = v2 || 11
    v3 = v3 || 22
}

更安全的作法是使用 typeof 檢查編程

// 流行的javaScript庫中均使用相似的模式
function demo2(v1, v2, v3){
    v2 = (typeof v2 !== 'undefined') ? v2 : 11
    v3 = (typeof v3 !== 'undefined') ? v3 : 22
}

無命名參數

不容易發現下面的函數 pick 能夠接受任意數量的參數數組

// desc: 取出obj對象中的指定屬性
function pick(obj){
    const result = {}
    for(let i = 1, l = arguments.length; i < l; i++){
        result[arguments[i]] = obj[arguments[i]]
    }
    return result;
}
const obj = {name: 'aaron', age:18, sex: 'man'}

// 將obj對象中的name和sex屬性取出
// { name: 'aaron', sex: 'man' }
console.log(pick(obj, 'name', 'sex'))

函數建立

建立函數的方式不太簡潔,期待能少寫一些字符來建立下面的函數安全

let getValue = function(v){
    return v
}

let sum = function(v1, v2){
    return v1 + v2
}

let noop = function(){}

解決方法

默認參數

es6能在形參中指定默認值,就像這樣:編程語言

function demo2(v1, v2 = 11, v3 = 22){
    console.log(v2)
    console.log(v3)
}
// 11 22
demo2('v1')
// 11 33
demo2('v1', undefined, 33)
// null 22
demo2('v1', null)

:全等於 undefined 才使用默認值函數

無命名參數

不定參數:函數的參數前加三個點(...)就表示這是一個不定參數,該參數是一個數組oop

用不定參數解決上面pick函數的問題:不容易發現pick()能夠接受任意數量的參數

// desc: 取出obj對象中的指定屬性
function pick(obj, ...keys){
    const result = {}
    for(let i = 0, l = keys.length; i < l; i++){
        result[keys[i]] = obj[keys[i]]
    }
    return result;
}
const obj = {name: 'aaron', age:18, sex: 'man'}

// 將obj對象中的name和sex屬性取出
// { name: 'aaron', sex: 'man' }
console.log(pick(obj, 'name', 'sex'))

:不定參數有兩條限制

  • 每一個函數只能聲明一個不定參數,且必定要放在全部參數後面
  • 不定參數不能用於對象字面量 setter 中
// 錯誤:不定參數不在末尾
function pick(obj, ...keys, last){}

// 錯誤(之因此這麼限制,是由於對象字面量 setter 的參數有且只能有一個)
let obj = {
    set name(...v){
        console.log('hello')
    }
}
obj.name = 1;

函數建立

es6提供一種建立函數的新語法,即箭頭函數,更加輕量,簡介。

箭頭函數的語法多變,根據實際場景由多種形式。全部變體都由函數參數、箭頭和函數體組成

let getValue = v => v

// 實際上至關於

let getValue = function(v){
    return v
}
let sum = (v1, v2) => v1 + v2;

// 實際上至關於

let sum = function(v1, v2){
    return v1 + v2
}
let noop = () => {}

// 實際上至關於

let noop = function(){}
let getNumber = () => 100

// 實際上至關於

let getNumber = function(){
    return 100
}

若是想經過箭頭函數返回一個對象字面量,須要用將對象字面量包裹在括號中

let demo = id => ({id: id, age: 18})

// 實際上至關於

let demo = function(id){
    return {id: id, age: 18}
}

箭頭函數沒有 this,箭頭函數的 this 由外圍最近一層非箭頭函數決定

// 箭頭函數的this,就是函數init中的this
let obj = {
    id: 11,
    init: function(){
        document.addEventListener('click', evt => {
            console.log(this.id) // 11
        })
    }
}
obj.init()

箭頭函數也沒有superargumentsnew.target,這些值與 this 同樣,都有外圍最近一層非箭頭函數決定

不能經過 new 關鍵字調用,由於頭函數沒有[[Constructor]],因此不能被用做構造函數

const Sum = (v1, v2) => v1 + v2
new Sum() // 報錯

補充

默認參數

默認參數能夠傳非原始值

function getValue(){
    console.log('執行')
    return 11
}
/* 經過函數執行來獲得參數的默認值 */
function demo2(v1, v2 = getValue()){
    console.log(v2)
}
demo2('v1') // 執行 11
demo2('v1', 12)

默認參數的臨時死區

function getValue(v){
    return v
}
function add(first=getValue(second), second = 100){
    const result = first + second
    console.log(result)
    return result
}
add(1, 2) // 3 {1}
add(undefined, 2) // 報錯 {2}
add(10) // 110 {3}

默認參數也存在講let和const時介紹的臨時死區TDZ

// {1}:表示調用add(1, 2)時的js代碼
let first = 1
let second = 1;

// {2}: 表示調用add(undefined, 2)時的js代碼
let first = getValue(second) // second還在臨時死區中
let second = 2

加強的Function

Function構造函數,咱們一般用它來構造新的函數,這種構造函數接受字符串的形式,分別是函數的參數和函數體

const add = new Function('v1', 'v2', 'return v1 + v2')
console.log(add(10, 20)) // 30

es6中Function構造函數也支持默認參數和不定參數

// 默認參數
const add = new Function('v1', 'v2 = 20', 'return v1 + v2')
console.log(add(10)) // 30

// 不定參數
const add = new Function('...keys', 'return keys[0] + keys[1]')
console.log(add(10, 20)) // 30

展開運算符

展開運算符與函數中的不定參數很類似

console.log(Math.max(1, 3, 2)); // 3

// 展開運算符
console.log(Math.max(...[1, 3, 2])) // 3
console.log(Math.max(...[1, 3, 2], 4)) // 4

不定參數是將各自獨立的參數整合成一個數組,展開運算符是將一個數組打散後做爲獨立的參數傳入函數

判斷函數是否用new調用

es6中引入 new.target 來解決判斷函數是否經過new關鍵字調用的問題

// es5中限制函數必須經過new調用的實現以下:
function People(){
    if(this instanceof People){
        console.log('created')
    }else{
        throw new Error('必須經過 new 調用')
    }
}

const p1 = new People() // created
People.call(p1) // created(有效)

當調用函數的[[Constructor]]方法時,new.target被賦值爲new操做符的目標,若是調用[[Call]]方法,則new.target的值爲undefined

function People(){
    if(new.target === People){
        console.log('created')
    }else{
        throw new Error('必須經過 new 調用')
    }
}

const p1 = new People() // created
People.call(p1) // Error: 必須經過 new 調用

:js函數有兩個內部方法:[[Call]]和[[Construct]],當經過new關鍵字調用函數時,執行[[Construct]]函數,它負責建立稱做實例的新對象;若是不經過new關鍵字調用函數,則執行[[Call]]函數,從而直接執行代碼中的函數體

其餘章節請看:

es6 快速入門 系列

相關文章
相關標籤/搜索