你真的了解ES6函數(shù)特性么?

hello大家好谷扣,又見面了土全。

假期轉(zhuǎn)瞬即逝,年后開工的第一天会涎,早上是真的不想起床吖裹匙,為了不遲到閉著眼睛就穿衣服。

好啦好啦末秃,步入正題啦概页,打起精神哦!

前言

函數(shù)是所有編程語言中重要的組成部分蛔溃,在Es6出現(xiàn)之前 JavaScript的函數(shù)語法一直沒有太大的變化绰沥,從而遺留了很多問題和隱晦的做法,導(dǎo)致實現(xiàn)一些功能需要編寫很多代碼贺待。

函數(shù)形參默認(rèn)值

JavaScript函數(shù)有一個特別的地方徽曲,就是無論在函數(shù)形參里定義了多少參數(shù),都可以傳入任意數(shù)量的參數(shù)麸塞,但是有的情況下秃臣,我們的參數(shù)只是可填,這樣的話我們還在函數(shù)體呢寫一堆邏輯從而導(dǎo)致代碼冗余,還好Es6版本出現(xiàn)了函數(shù)默認(rèn)值奥此。

我們用Es5和Es6代碼來比對一下

Es5處理默認(rèn)參數(shù)

function person(name, age) {
    name = typeof(name) != "undefined" ? name : `蛙人${+ new Date()}`
    age = typeof(age) != "undefined" ? age : 24
    
}
person()

上面example中是Es5這樣處理默認(rèn)參數(shù)值的弧哎,假如我們參數(shù)多的話,這么寫代碼的話會造成非常冗余的稚虎,于是Es6就出現(xiàn)函數(shù)參數(shù)默認(rèn)值撤嫩。

Es6處理默認(rèn)參數(shù)

function person(name = "蛙人", age = 24) {
    console.log(name, age)
}
person()  // 蛙人 24
person("張三", 30) // 張三 30
person(null, null) // null null

上面example是Es6中處理的默認(rèn)參數(shù),可以看到代碼非常簡化蠢终,上面代碼可以看到參數(shù)傳入了null序攘,對于默認(rèn)參數(shù)null也是一個合法值,這種情況下只有函數(shù)參數(shù)為undefined時才會使用默認(rèn)值寻拂。

函數(shù)參數(shù)表達式

關(guān)于默認(rèn)參數(shù)值程奠,最有趣的特性可能就是非原始值傳參了,也可以把默認(rèn)參數(shù)定義為函數(shù)or 變量祭钉。

function defaultName() {
    return "蛙人"
}
function person(name = defaultName()) {
    console.log(name)
}
person("張三") // 張三
person() // 蛙人

需要注意的是瞄沙,默認(rèn)參數(shù)的表達式不是一創(chuàng)建函數(shù)就立刻執(zhí)行的,而是當(dāng)該函數(shù)person被調(diào)用的時候并且沒有傳入?yún)?shù)才會執(zhí)行慌核。

上面example中距境,如果不傳參才會調(diào)用默認(rèn)值的defaultName函數(shù)。

下面來看一下默認(rèn)參數(shù)傳入變量遂铡。

let defaultName = "蛙人"
function person(name = defaultName) {
     console.log(name)
}
person("張三") // 張三
person() // 蛙人
function person(name, nickName = name) {
     console.log(name, nickName)
}
person("張三") // 張三 張三
person("蛙人", "掘金蛙人") // 蛙人 掘金蛙人

上面example中肮疗,第一個代碼塊的里面我們都能看的懂,只不過把之前的函數(shù)換成了變量扒接∥被酰看第二個代碼塊里的代碼,我們把nickName參數(shù)默認(rèn)值設(shè)置成了第一個參數(shù)name參數(shù)钾怔,這是在引用參數(shù)默認(rèn)值的時候碱呼,只允許引用前面參數(shù)的值,相當(dāng)于函數(shù)參數(shù)就是定義的變量宗侦,我們后面的變量可以訪問前面變量的愚臀,但是只限制在于當(dāng)前作用域中,這個函數(shù)形參里就是當(dāng)前作用域矾利。我們再看一個例子姑裂。

function person(name = nickName, nickName) {
     console.log(name, nickName)
}
person("張三") // 張三 張三

上面example中,第一個參數(shù)默認(rèn)值是第二個參數(shù)男旗,這時運行會拋出一個錯誤舶斧,因為這時在定義第二個變量前去訪問,會造成暫時死區(qū)察皇,如果不明白暫時死區(qū)的可以去看我的上一篇文章茴厉。《一看就懂的var泽台、let、const三者區(qū)別》

函數(shù)參數(shù)默認(rèn)值對arguments的影響

當(dāng)使用函數(shù)默認(rèn)參數(shù)時矾缓,arguments對象的行為會與以往不同

Es5非嚴(yán)格模式下使用arguments

Es5非嚴(yán)格模式下怀酷,函數(shù)命名參數(shù)的變化會體現(xiàn)在arguments對象上,arguments獲取的是當(dāng)前函數(shù)的實參嗜闻,arguments在非嚴(yán)格模式下它跟形參是映射關(guān)系蜕依,就是形參有變化arguments跟著變。

function test(a, b) {
    console.log(a == arguments[0]) // true
    console.log(b == arguments[1]) // true
    a = "a"
    b = "b"
    console.log(arguments) // ["a", "b"]
}
test(1, 2)

上面example中泞辐,在非嚴(yán)格模式下笔横,命名參數(shù)的變化會同步更新到arguments對象中。當(dāng)a參數(shù)的變化咐吼,會映射到arguments[0]對象上。

Es5嚴(yán)格模式下使用arguments

下面我們再來看一下嚴(yán)格模式下的arguments

 function test(a, b) {
    'use strict';

    console.log(arguments)  // [1, 2]
    b = 10
    console.log(arguments) // [1, 2]
}
test(1, 2)

上面example是嚴(yán)格模式下的商佑,可以看出當(dāng)我們改變參數(shù)b時锯茄,再次打印arguments對象,它還是初始化值茶没。在嚴(yán)格模式下JavaScript中取消了arguments對象這個令人困惑的行為肌幽,無論參數(shù)如何變化,arguments對象不再隨之改變抓半。

Es6中使用默認(rèn)參數(shù)值對arguments的影響

在Es6中喂急,如果一個函數(shù)使用了默認(rèn)參數(shù)值,那么arguments對象的行為都將與JavaScript中的嚴(yán)格模式下保持一致笛求。

 function test(a, b = 2) {
    a = 12
    b = 10
    console.log(arguments) // [1]
}
test(1)

上面example中廊移,arguments對象打印出[1]是因為arguments對象獲取的是實參,我們可以看到實參參數(shù)就傳了一個值探入,所以arguments對象就只有一個值狡孔。再看第二點,ab的參數(shù)都改變了值蜂嗽,但是arguments對象還是沒有改變苗膝,這就是上面說的,如果一個函數(shù)使用了默認(rèn)參數(shù)值植旧,那么arguments對象的行為都將與JavaScript中的嚴(yán)格模式下保持一致辱揭。

處理無命名參數(shù)

在js中函數(shù)參數(shù)數(shù)量是任意的,當(dāng)傳入更少的數(shù)量病附,默認(rèn)參數(shù)的特性可以有效的簡化函數(shù)聲明的代碼问窃。當(dāng)傳入更多的數(shù)量,Es6也同樣提供了更好的方案胖喳。

Es5中獲取無命名參數(shù)

function test(a, b, c) {
    console.log(arguments) // [1, 2, 3]
}
test(1, 2, 3)

上面example中泡躯,arguments對象雖然也可以實現(xiàn)獲取所有的參數(shù),但是呢如果我們想獲取第二個參數(shù)之后的所有參數(shù),那么還得循環(huán)去排除较剃。

Es6中獲取無命名參數(shù)

function test(...parmas) {
    console.log(params) // [1, 2, 3, 4]
}
test(1, 2, 3, 4)
function test(a, b, ...params) {
    console.log(params)
}
test(1, 2, 3, 4)

上面example中咕别,第一個代碼塊里實現(xiàn)了在Es6中獲取全部的參數(shù),可是還不滿足我們的需求写穴。那么看第二個代碼塊里的代碼就實現(xiàn)了惰拱,我們獲取第二個參數(shù)后面所有的參數(shù)。

Es6獲取無命名參數(shù)弊端

首先啊送,每一個函數(shù)只能聲明一個獲取不定參數(shù)偿短,而且只能放在函數(shù)的末尾,否則會報錯馋没。

function test(...params, a, b) {
    
}
test()

上面example中昔逗,會拋出錯誤,聲明了不定參數(shù)數(shù)之后篷朵,就不能繼續(xù)在后面聲明參數(shù)勾怒。

還有一點,不定參數(shù)不能定義在對象字面量的setter中声旺,因為setter函數(shù)只接收一個函數(shù)笔链,寫成不定參數(shù)之后就會是一個數(shù)組,這樣就會導(dǎo)致程序異常腮猖。

let obj = {
  set name(...params) {

  }
}

函數(shù)name屬性

JavaScript中所有的函數(shù)都有一個name屬性鉴扫,該屬性保存的是該函數(shù)名稱的字符串。沒有名稱的函數(shù)也仍然有name屬性澈缺,該name屬性值為空字符串坪创。

function person() {}
let test = function() {}

console.log(person.name) // person
console.log(test.name) // test

上面example中,person函數(shù)name屬性值為"person",對應(yīng)著聲明時的函數(shù)名稱谍椅。匿名函數(shù)表達式test函數(shù)的name名稱误堡,對應(yīng)著被賦值為匿名函數(shù)的變量。

name屬性的特殊情況

我原來以為每個函數(shù)的name名稱都是對應(yīng)著當(dāng)前的函數(shù)名雏吭,后來發(fā)現(xiàn)并不是這么回事锁施。下面來看一下函數(shù)的特殊情況

var person = {
    get getName() {
        return "蛙人"
    }
}
console.log(Object.getOwnPropertyDescriptor(person, 'getName').get.name)  // get getName

function test() {}
console.log(test.bind().name) // bound test

上面example中,person.getName是一個取值函數(shù)getter杖们,所以它的函數(shù)名稱get getName悉抵,如果是setter函數(shù)的話那么名稱會有帶有前綴set。通過bind創(chuàng)建的函數(shù)摘完,它的名稱帶有"bound"前綴姥饰。

箭頭函數(shù)

Es6中箭頭函數(shù)是其中最有趣的特性,箭頭函數(shù)是一種使用箭頭=>定義函數(shù)的新語法孝治,但是它與傳統(tǒng)的JavaScript函數(shù)有些不同列粪,具體看下面幾點审磁。

  • 沒有thissuper岂座、arguments
  • 不能通過new關(guān)鍵字調(diào)用
  • 沒有原型prototype
  • 不可以改變this指向
  • 不支持重復(fù)的命名參數(shù)

箭頭函數(shù)和傳統(tǒng)函數(shù)一樣都有一個name屬性态蒂,這一點是不變的费什。

箭頭函數(shù)語法

let person = () => "蛙人"

// 相當(dāng)于下代碼

function person() {
    return "蛙人"
}

上面example中钾恢,當(dāng)箭頭函數(shù)右側(cè)的表達式求值后會立即返回。

箭頭函數(shù)參數(shù)

let getName = val => val

// 相當(dāng)于下代碼

function getName(val) {
    return val
}

當(dāng)箭頭函數(shù)只有一個參數(shù)時,就可以省略括號巡球,直接寫參數(shù)名。如果要傳入兩個或多個參數(shù)吴超,則就需要帶上括號【ㄗ瑁看下面例子

let sum = (a, b) => a + b

// 相當(dāng)于下代碼

function sun(a, b) {
    return a + b
}

如果你想返回一個對象字面量鸟悴,可以這樣寫

let getObj = () => ({name: "蛙人", age: 24}) // {name: "蛙人", age: 24}

// 相當(dāng)于下代碼

function getObj() {
    return {
        name: "蛙人",
        age: 24
    }
}

箭頭函數(shù)沒有this

箭頭函數(shù)的this值细诸,取決于函數(shù)外部非箭頭函數(shù)的this值沛贪,如果上一層還是箭頭函數(shù),那就繼續(xù)往上找震贵,如果找不到那么this就是window對象

let person = {
    test: () => {
        console.log(this)
    },
    fn() {
        return () => {
            console.log(this)
        }
    }
}
person.test()  // window
person.fn()()  // person對象

上面example中利赋,可以清楚的看到箭頭沒有this,那么它的this只會去找外層的非箭頭函數(shù)的函數(shù)猩系。

箭頭函數(shù)沒有arguments對象

同樣箭頭函數(shù)也沒有arguments對象媚送,但是如果它外層還有一層非箭頭函數(shù)的話,就會去找外層的函數(shù)的arguments對象寇甸, 如下

let test1 = () => console.log(arguments)  // 執(zhí)行該函數(shù)會拋出錯誤


function test2(a, b, c) {
    return () => {
        console.log(arguments) // [1, 2, 3]
    }
}
test2(1, 2, 3)()

上面example中塘偎,可以清楚的看到當(dāng)前的箭頭函數(shù)沒有arguments對象疗涉,然而就去它的外層去找非箭頭函數(shù)的函數(shù)。注意:箭頭函數(shù)找arguments對象只會找外層非箭頭函數(shù)的函數(shù)吟秩,如果外層是一個非箭頭函數(shù)的函數(shù)如果它也沒有arguments對象也會中斷返回咱扣,就不會在往外層去找了》宄ⅲ看下面例子

function test(a) {
    return function() {
        return () => {
            console.log(arguments) // []
        }
    }
}
test(1)()()

上面example中可以看到偏窝,里面的箭頭函數(shù)往外層找非箭頭函數(shù)的函數(shù),然后不管外層這個函數(shù)有沒有arguments對象都會返回武学。只有它是非箭頭函數(shù)就可以祭往,如果外層是箭頭函數(shù)還會繼續(xù)往外層找。

箭頭函數(shù)不能用new關(guān)鍵字聲明

let test = () => {}
new test() // 拋出錯誤火窒,找不到constructor對象

箭頭函數(shù)沒有原型prototype

切記硼补,箭頭函數(shù)沒有原型,有可能面試官會問熏矿,JavaScript中所有的函數(shù)都有prototype屬性嗎

let test = () => {}
test.prototype // undefined

箭頭函數(shù)不能改變this指向

let person = {}
let test = () => console.log(this)

test.bind(person)()
test.call(person)
test.apply(person)

上面example中已骇,改變this指向的方法都不會拋出錯誤,但是都無效票编,都不能改變this指向褪储。

箭頭函數(shù)不能重復(fù)命名參數(shù)

let sum = (a, a) => {} // 拋出錯誤,參數(shù)不能重復(fù)

覺得寫的不錯那就點個贊叭慧域!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鲤竹,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子昔榴,更是在濱河造成了極大的恐慌辛藻,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件互订,死亡現(xiàn)場離奇詭異吱肌,居然都是意外死亡,警方通過查閱死者的電腦和手機仰禽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進店門氮墨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人坟瓢,你說我怎么就攤上這事勇边。” “怎么了折联?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵粒褒,是天一觀的道長。 經(jīng)常有香客問我诚镰,道長奕坟,這世上最難降的妖魔是什么祥款? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮月杉,結(jié)果婚禮上刃跛,老公的妹妹穿的比我還像新娘。我一直安慰自己苛萎,他們只是感情好桨昙,可當(dāng)我...
    茶點故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著腌歉,像睡著了一般蛙酪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上翘盖,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天桂塞,我揣著相機與錄音,去河邊找鬼馍驯。 笑死阁危,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的汰瘫。 我是一名探鬼主播狂打,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼混弥!你這毒婦竟也來了菱父?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤剑逃,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后官辽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛹磺,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年同仆,在試婚紗的時候發(fā)現(xiàn)自己被綠了萤捆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片誉尖。...
    茶點故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡河咽,死狀恐怖卧秘,靈堂內(nèi)的尸體忽然破棺而出凰荚,到底是詐尸還是另有隱情革骨,我是刑警寧澤决侈,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布超升,位于F島的核電站负蠕,受9級特大地震影響干像,放射性物質(zhì)發(fā)生泄漏帅腌。R本人自食惡果不足惜驰弄,卻給世界環(huán)境...
    茶點故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望速客。 院中可真熱鬧戚篙,春花似錦、人聲如沸溺职。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽浪耘。三九已至乱灵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間点待,已是汗流浹背阔蛉。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留癞埠,地道東北人状原。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像苗踪,于是被迫代替她去往敵國和親颠区。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,666評論 2 350

推薦閱讀更多精彩內(nèi)容