函式引數預設值
(1) es5中模擬引數預設值:
function fn(name, count){
name = name || 'xiao ming'
count= count|| 1
console.log(name, count)
}
複製程式碼
這樣可以為沒有傳入的引數,設定為預設值。這種方式的問題:如果count傳入0,即使這個值是合法的,但也會被設定為預設值1。 改進後:
function fn(name, count){
name = typeof name !== 'undefined' ? name : 'xiao ming'
count = typeof count !== 'undefined' ? count : 1
console.log(name, count)
}
複製程式碼
(2) es6的做法:
function fn(name = 'xiao ming', count = 1){
console.log(name, count)
}
// name使用預設值
fn(undefined, 18)
複製程式碼
掃盲: null是一個有效引數,傳入null並不會使用預設引數
(3) 命名引數與arguments
的關係
es5非嚴格模式下,修改命名引數,會同步更新到arguments物件中; 而在es6或者嚴格模式中,命名引數和arguments是分離的
function fn1(name, count) {
name = 'li si'
count = 5
console.log(arguments[0])
console.log(arguments[1])
}
fn1('xiao wang', 4)
// 非嚴格模式下
// li si
// 5
// 嚴格模式下或es6環境中
// xiao wang
// 4
複製程式碼
(4) 函式預設表示式
function count(){return 6}
function fn1(name, count = count()) {
console.log(name)
console.log(count)
}
fn1('xiao wang')
// 'xiao wang'
// 5
複製程式碼
掃盲: 1. 引數、引數預設值、引數預設表示式都在同一個獨立的作用域內; 2. 引數作用域中存在臨時性死區,即後面的引數可以引用到前面的引數,反之不可以; 3. 引數作用域引用不到函式體內的變數
證明獨立作用域的例子:
function fn(a, cb = () => { a.b = 1; console.log(a) }) {
var a = { a: 1 }
cb()
console.log(a)
}
fn({ c: 3 })
// { c: 3, b: 1 }
// { a: 1 }
複製程式碼
cb
執行時,獲取到的物件a
並不是函式體內新定義的,而是傳入的引數a
,所以他們是在同一獨立作用域的
無名引數
(1) es5中使用arguments獲取不定數量的引數
// 如果沒有註釋,很難發現函式需要傳入無命名引數
function fn(arr){
// i 從 1開始,需要跳過 arr這個命名引數
for(let i = 1, len = arguments.length; i < len; i++){
arr.push(arguments[i])
}
return arr;
}
console.log(fn([3],4,5,6,7)) // [3,4,5,6,7]
複製程式碼
存在的問題:
- 並不容易發現函式,需要傳入不定量引數;
- 如果有命名引數,arguments中既包含命名引數也包含無名引數,還需要拆分獲取
(2) es6中,使用不定引數
在引數前加三個點...
,表明這是一個不定引數,這個引數為陣列,包含著自它以後傳入的引數。
並且解決了上述es5
中的問題
function fn(arr, ...items){
for(let i = 0, len = items.length; i < len; i++){
arr.push(items[i])
}
return arr;
}
console.log(fn([3],4,5,6,7)) // [3,4,5,6,7]
複製程式碼
不定引數的限制:
- 每個函式只能定義一個不定引數,而且只能處於所有引數末尾。錯誤示範:
function fn(a, ...b, c){}
- 物件的
setter
函式不能使用不定引數。錯誤示範:let obj = {set name(...value){}}
掃盲:
- 無論是否使用不定引數,
arguments
總是包括所有傳入的引數- 函式的**
length
屬性**,表示命名引數的數量,跟不定引數無關
函式的name
屬性
function fn(){}
name為fn
let fn = function (){}
name為fn
let fn = function fn1(){}
name為fn1
,因為函式名比被賦值的變數權重高let obj = {get firstName(){}, sayName(){}}
。obj.firstName
為getter函式,所以name為get firstName
;obj.sayName
name為sayName
- 通過
bind()
建立的函式,name會帶有bound
字首。fn.bind()
name為bound fn
- 通過
Function()
建立的函式,name為anonymous
。new Function()
name為anonymous
掃盲:函式name屬性不一定能獲取對函式的引用,它只是協助除錯用的額外資訊
函式的多重用途
箭頭函式
相關語法就不再贅述
與普通函式的區別:
- 沒有
this、super、arguments
繫結,這些值都由外層的非箭頭函式決定- 不能使用new關鍵詞呼叫;沒有原型;函式體內沒有
new.target
。因為箭頭函式沒有[[construct]]
方法,所以不能當做建構函式呼叫。- 不可以改變this指向。箭頭函式的this指向,只跟函式定義時的環境有關,跟使用環境無關,
call apply bind
也無力改變。
- 再也不用快取
this
了,再也不會有_this self that
等各式各樣的變數了。- 說到這裡,突然想到了箭頭函式可以在
react
中繫結事件處理函式的this到元件例項 ,以及 普通函式的this與執行環境相關- 不可以使用yield命令,因此箭頭函式不能用作 Generator 函式。
- 不支援重名引數。es6與es5嚴格模式下都不支援函式引數重名。
// es5非嚴格模式下,引數重名情況 function fn(a,b,a){ console.log(a) console.log(b) console.log(arguments[0]) console.log(arguments[1]) console.log(arguments[2]) a = 4 console.log(arguments[0]) console.log(arguments[1]) console.log(arguments[2]) } fn(1,2,3) //3 //2 //1 //2 //3 //1 //2 //4 // 即 arguments[0]與 a解除了相關性 複製程式碼
雙冒號運算子
函式繫結運算子是並排的兩個冒號(::),雙冒號左邊是一個物件,右邊是一個函式。該運算子會自動將左邊的物件,作為上下文環境(即this物件),繫結到右邊的函式上面。
foo::bar;
// 等同於
bar.bind(foo);
foo::bar(...arguments);
// 等同於
bar.apply(foo, arguments);
複製程式碼