hello大家好,又見面了,
假期轉瞬即逝,年后開工的第一天,早上是真的不想起床吖,為了不遲到閉著眼睛就穿衣服,
好啦好啦,步入正題啦,打起精神哦!
前言
函式是所有編程語言中重要的組成部分,在Es6出現之前 JavaScript的函式語法一直沒有太大的變化,從而遺留了很多問題和隱晦的做法,導致實作一些功能需要撰寫很多代碼,
函式形參默認值
JavaScript函式有一個特別的地方,就是無論在函式形參里定義了多少引數,都可以傳入任意數量的引數,但是有的情況下,我們的引數只是可填,這樣的話我們還在函式體呢寫一堆邏輯從而導致代碼冗余,還好Es6版本出現了函式默認值,
我們用Es5和Es6代碼來比對一下
Es5處理默認引數
function person(name, age) {
name = typeof(name) != "undefined" ? name : `蛙人${+ new Date()}`
age = typeof(age) != "undefined" ? age : 24
}
person()
上面example中是Es5這樣處理默認引數值的,假如我們引數多的話,這么寫代碼的話會造成非常冗余的,于是Es6就出現函式引數默認值,
Es6處理默認引數
function person(name = "蛙人", age = 24) {
console.log(name, age)
}
person() // 蛙人 24
person("張三", 30) // 張三 30
person(null, null) // null null
上面example是Es6中處理的默認引數,可以看到代碼非常簡化,上面代碼可以看到引數傳入了null,對于默認引數null也是一個合法值,這種情況下只有函式引數為undefined時才會使用默認值,
函式引數運算式
關于默認引數值,最有趣的特性可能就是非原始值傳參了,也可以把默認引數定義為函式or 變數,
function defaultName() {
return "蛙人"
}
function person(name = defaultName()) {
console.log(name)
}
person("張三") // 張三
person() // 蛙人
需要注意的是,默認引數的運算式不是一創建函式就立刻執行的,而是當該函式
person被呼叫的時候并且沒有傳入引數才會執行,
上面example中,如果不傳參才會呼叫默認值的defaultName函式,
下面來看一下默認引數傳入變數,
let defaultName = "蛙人"
function person(name = defaultName) {
console.log(name)
}
person("張三") // 張三
person() // 蛙人
function person(name, nickName = name) {
console.log(name, nickName)
}
person("張三") // 張三 張三
person("蛙人", "掘金蛙人") // 蛙人 掘金蛙人
上面example中,第一個代碼塊的里面我們都能看的懂,只不過把之前的函式換成了變數,看第二個代碼塊里的代碼,我們把nickName引數默認值設定成了第一個引數name引數,這是在參考引數默認值的時候,只允許參考前面引數的值,相當于函式引數就是定義的變數,我們后面的變數可以訪問前面變數的,但是只限制在于當前作用域中,這個函式形參里就是當前作用域,我們再看一個例子,
function person(name = nickName, nickName) {
console.log(name, nickName)
}
person("張三") // 張三 張三
上面example中,第一個引數默認值是第二個引數,這時運行會拋出一個錯誤,因為這時在定義第二個變數前去訪問,會造成暫時死區,如果不明白暫時死區的可以去看我的上一篇文章,《一看就懂的var、let、const三者區別》
函式引數默認值對arguments的影響
當使用函式默認引數時,arguments物件的行為會與以往不同
Es5非嚴格模式下使用arguments
Es5非嚴格模式下,函式命名引數的變化會體現在arguments物件上,arguments獲取的是當前函式的實參,arguments在非嚴格模式下它跟形參是映射關系,就是形參有變化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中,在非嚴格模式下,命名引數的變化會同步更新到arguments物件中,當a引數的變化,會映射到arguments[0]物件上,
Es5嚴格模式下使用arguments
下面我們再來看一下嚴格模式下的arguments
function test(a, b) {
'use strict';
console.log(arguments) // [1, 2]
b = 10
console.log(arguments) // [1, 2]
}
test(1, 2)
上面example是嚴格模式下的,可以看出當我們改變引數b時,再次列印arguments物件,它還是初始化值,在嚴格模式下JavaScript中取消了arguments物件這個令人困惑的行為,無論引數如何變化,arguments物件不再隨之改變,
Es6中使用默認引數值對arguments的影響
在Es6中,如果一個函式使用了默認引數值,那么arguments物件的行為都將與JavaScript中的嚴格模式下保持一致,
function test(a, b = 2) {
a = 12
b = 10
console.log(arguments) // [1]
}
test(1)
上面example中,arguments物件列印出[1]是因為arguments物件獲取的是實參,我們可以看到實參引數就傳了一個值,所以arguments物件就只有一個值,再看第二點,a和b的引數都改變了值,但是arguments物件還是沒有改變,這就是上面說的,如果一個函式使用了默認引數值,那么arguments物件的行為都將與JavaScript中的嚴格模式下保持一致,
處理無命名引數
在js中函式引數數量是任意的,當傳入更少的數量,默認引數的特性可以有效的簡化函式宣告的代碼,當傳入更多的數量,Es6也同樣提供了更好的方案,
Es5中獲取無命名引數
function test(a, b, c) {
console.log(arguments) // [1, 2, 3]
}
test(1, 2, 3)
上面example中,arguments物件雖然也可以實作獲取所有的引數,但是呢如果我們想獲取第二個引數之后的所有引數,那么還得回圈去排除,
Es6中獲取無命名引數
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中,第一個代碼塊里實作了在Es6中獲取全部的引數,可是還不滿足我們的需求,那么看第二個代碼塊里的代碼就實作了,我們獲取第二個引數后面所有的引數,
Es6獲取無命名引數弊端
首先,每一個函式只能宣告一個獲取不定引數,而且只能放在函式的末尾,否則會報錯,
function test(...params, a, b) {
}
test()
上面example中,會拋出錯誤,宣告了不定引數數之后,就不能繼續在后面宣告引數,
還有一點,不定引數不能定義在物件字面量的setter中,因為setter函式只接收一個函式,寫成不定引數之后就會是一個陣列,這樣就會導致程式例外,
let obj = {
set name(...params) {
}
}
函式name屬性
在JavaScript中所有的函式都有一個name屬性,該屬性保存的是該函式名稱的字串,沒有名稱的函式也仍然有name屬性,該name屬性值為空字串,
function person() {}
let test = function() {}
console.log(person.name) // person
console.log(test.name) // test
上面example中,person函式name屬性值為"person",對應著宣告時的函式名稱,匿名函式運算式test函式的name名稱,對應著被賦值為匿名函式的變數,
name屬性的特殊情況
我原來以為每個函式的name名稱都是對應著當前的函式名,后來發現并不是這么回事,下面來看一下函式的特殊情況
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是一個取值函式getter,所以它的函式名稱get getName,如果是setter函式的話那么名稱會有帶有前綴set,通過bind創建的函式,它的名稱帶有"bound"前綴,
箭頭函式
Es6中箭頭函式是其中最有趣的特性,箭頭函式是一種使用箭頭=>定義函式的新語法,但是它與傳統的JavaScript函式有些不同,具體看下面幾點,
- 沒有
this、super、arguments - 不能通過
new關鍵字呼叫 - 沒有原型
prototype - 不可以改變
this指向 - 不支持重復的命名引數
箭頭函式和傳統函式一樣都有一個name屬性,這一點是不變的,
箭頭函式語法
let person = () => "蛙人"
// 相當于下代碼
function person() {
return "蛙人"
}
上面example中,當箭頭函式右側的運算式求值后會立即回傳,
箭頭函式引數
let getName = val => val
// 相當于下代碼
function getName(val) {
return val
}
當箭頭函式只有一個引數時,就可以省略括號,直接寫引數名,如果要傳入兩個或多個引數,則就需要帶上括號,看下面例子
let sum = (a, b) => a + b
// 相當于下代碼
function sun(a, b) {
return a + b
}
如果你想回傳一個物件字面量,可以這樣寫
let getObj = () => ({name: "蛙人", age: 24}) // {name: "蛙人", age: 24}
// 相當于下代碼
function getObj() {
return {
name: "蛙人",
age: 24
}
}
箭頭函式沒有this
箭頭函式的this值,取決于函式外部非箭頭函式的this值,如果上一層還是箭頭函式,那就繼續往上找,如果找不到那么this就是window物件
let person = {
test: () => {
console.log(this)
},
fn() {
return () => {
console.log(this)
}
}
}
person.test() // window
person.fn()() // person物件
上面example中,可以清楚的看到箭頭沒有this,那么它的this只會去找外層的非箭頭函式的函式,
箭頭函式沒有arguments物件
同樣箭頭函式也沒有arguments物件,但是如果它外層還有一層非箭頭函式的話,就會去找外層的函式的arguments物件, 如下
let test1 = () => console.log(arguments) // 執行該函式會拋出錯誤
function test2(a, b, c) {
return () => {
console.log(arguments) // [1, 2, 3]
}
}
test2(1, 2, 3)()
上面example中,可以清楚的看到當前的箭頭函式沒有arguments物件,然而就去它的外層去找非箭頭函式的函式,注意:箭頭函式找arguments物件只會找外層非箭頭函式的函式,如果外層是一個非箭頭函式的函式如果它也沒有arguments物件也會中斷回傳,就不會在往外層去找了,看下面例子
function test(a) {
return function() {
return () => {
console.log(arguments) // []
}
}
}
test(1)()()
上面example中可以看到,里面的箭頭函式往外層找非箭頭函式的函式,然后不管外層這個函式有沒有arguments物件都會回傳,只有它是非箭頭函式就可以,如果外層是箭頭函式還會繼續往外層找,
箭頭函式不能用new關鍵字宣告
let test = () => {}
new test() // 拋出錯誤,找不到constructor物件
箭頭函式沒有原型prototype
切記,箭頭函式沒有原型,有可能面試官會問,JavaScript中所有的函式都有prototype屬性嗎
let test = () => {}
test.prototype // undefined
箭頭函式不能改變this指向
let person = {}
let test = () => console.log(this)
test.bind(person)()
test.call(person)
test.apply(person)
上面example中,改變this指向的方法都不會拋出錯誤,但是都無效,都不能改變this指向,
箭頭函式不能重復命名引數
let sum = (a, a) => {} // 拋出錯誤,引數不能重復
覺得寫的不錯那就點個贊叭!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/261075.html
標籤:其他
