重學ES6 函式的擴充套件(上)

legendaryedu發表於2019-04-18

函式引數的預設值

基本用法

在ES6之前,我們是這樣來做的

function log( x, y){
    y = y || 'world'
    console.log(x, y)
}

log('hello') //hello world
log('hello', 'china') // hello china
log('hello','') // hello world
複製程式碼

以上寫法會有一個問題,就是當我們傳進去一個y值,但是其對應的布林值為false,例如 log('hello',''),結果被修改為了預設值! 所以,為了避免這個問題,我們替換如下語句

if(typeof y === 'undefined'){
    y = 'world'
}
複製程式碼

在ES6裡面就簡單多了,可以直接在引數設定預設值

function log(x, y = 'world') {
    console.log(x ,y)
}
log('hello') //hello world
log('hello', 'china') //hello china
log('hello','') // hello
複製程式碼

有一點需要注意 引數預設值不是傳值的,而是每次重新計算預設值表示式的值,引數預設值是“惰性求值的”

let x = 99

function foo(p = x + 1){
    console.log(p)
}

foo() //100

x = 100

foo() //101

//引數 p 的預設值是 x+1 每次呼叫函式 foo 都會重新計算 x+1 ,而不是預設 p 等於 100
複製程式碼

注意:引數變數是預設宣告的,在函式體中,不能再用 let const 進行宣告,也 不允許有同名引數。

結合解構

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

foo({}) // undefined 5
foo({x:1}) // 1, 5
foo({x: 1, y: 3}) // 1, 3
foo() //報錯
複製程式碼

只有函式的引數是一個物件時,變數x y 才會通過解構賦值生成。如果函式呼叫時,引數不是物件,變數x y 就不會生成,會報錯。

在前面文章 重學ES6 解構我們他提到過函式引數的預設值,jQuery ajax的解構

這裡再用一個新的API寫一遍

function fetch(url,{body = '', metthod = 'GET', headers = {}}){
    console.log( method )
}

fetch('http://example.com', {}) // GET
fetch('http://example.com') // 報錯
複製程式碼

這個寫法不能省略第二個引數~那就太不好了。。。所以,我們要再結合函式的預設值,就可以省略第二個引數了

function fetch(url,{body = '', metthod = 'GET', headers = {}} = {}){
    console.log( method )
}

fetch('http://example.com', {}) // GET
fetch('http://example.com') // GET
複製程式碼

注意:在函式傳參解構中,只要傳入實際引數,那麼就拿傳入的實際引數進行解構,如果沒有傳入實際引數,且引數寫了預設值,函式引數得到值是 undefined 時,被賦予預設值。

// demo 1
function m1 ({x = 0,y = 0} = {}){
    return [x, y]
}

// demo 2
function m2 ({x, y} = {x: 0, y: 0}){
    return [x, y]
}

//x y 都無值
m1({}) //[0, 0]
m2({}) // 沒有寫預設值,對實參進行解構,[undefined, undefined]

m1({z: 3}) // [0, 0]
m2({z: 3}) // [undefined, undefined]
複製程式碼

預設引數位置

通常,定義了預設值的引數應該是函式的尾引數。這樣可以看出到底省略了哪些引數。

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

f() // [undefined, undefined, 1]
複製程式碼

函式的 length

指定了預設值以後,函式的 length 屬性將返回沒有指定預設值的引數個數。指定了預設值後,length屬性將失真

(function (a) {}).length //1
(function (a = 5)).length // 0
(function (b ,c ,a = 5)).length // 2
複製程式碼

length 屬性 含義是 “函式預期傳入的參 數個數” ,某個引數指定預設值以後,函式傳入引數個數就不包含這個了,rest引數也不會計入length屬性

作用域

設定了引數的預設值後,函式進行初始化時,引數會形成一個單獨的作用域。等到初始化結束,這個作用域就會消失。這種語法行為在不設定引數時是不會出現的。

var x= 1

function f(x,  y = x){  //相當於 let x 
    console.log(y)
}

f(2)
複製程式碼
// 如果此時全域性 x 不存在,就報錯了
function f(y = x){  //相當於 let y = x 
    console.log(y)
}

f()  // x is nit defined
複製程式碼
var x = 1

function f(x = x){  //相當於 let x = x  暫時性死區
    console.log(x)
}

f()  // x is nit defined
複製程式碼

如果引數是一個函式

let foo = 'ourter'

function bar (func = () => foo){ //在這裡,函式裡面的foo沒有定義,所以foo指向外層的 foo
    let foo = 'inner'
    console.log(func())
}

bar()
複製程式碼

又一個例子

此例子,x共有3個,全域性作用域下 foo函式引數作用域 還有 foo函式內部作用域,共三個,互不相同

var x =1

function foo(x, y = function() { x = 2}){
    var x = 3
    y()
    console.log(x)
}

foo() // 3
x // 1
複製程式碼

但是,如果去掉 foo 函式 內部的 var x = 3 的 var,那麼就剩下兩個不同的x,即:全域性下的x 和 函式 foo 引數作用域下的x ,因為函式內部的 x 和 函式引數的x 已經是同一個x

var x =1

function foo(x, y = function() { x = 2}){
    x = 3
    y()
    console.log(x)
}

foo() // 2
x // 1
複製程式碼

兩個例子都不會影響外部全域性變數x的值。

應用

引數預設值,可以指定某一個引數不能省略,如果省略了,就跑出一個錯誤

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

function foo(mustBeProvided = throwIfMissing()){
    return mustBeProvided
}

foo()
複製程式碼

rest 引數

es6 引入了 rest引數,(形式為 ...變數名),用於獲取函式的多餘引數,也就不需要使用 arguments 引數物件了。 rest引數搭配的變數是一個陣列,該變數將多餘的引數放入其中。

function add(...values){
    let sum = 0
    for(var val of values){
        sum += val
    }
    return sum
}
add(1,2,3) // 6
複製程式碼

幾個例子

之前,用arguments的寫法

// Array.prototype.slice.call(arguments)  將引數轉化為陣列
// array.sort
function sortNumbers() {
    return Array.prototype.slice.call(arguments).sort()
}

// rest 引數的寫法
//...numbers 將numbers 轉化為陣列
const sortNumbers = (...numbers) => numbers.sort()
複製程式碼

rest引數改寫 push

function push(array,...items){
    items.forEach(function(item){
        array.push(item)
    })
}

var a = []

push(a,1,2,3)
複製程式碼

rest 引數之後,不能再有其他引數,所以,rest只能是最後一個引數。而且,函式的length,不包括rest引數。

相關文章