一、函數(shù)參數(shù)的用法
1、參數(shù)默認(rèn)值的設(shè)置芜繁,與ES5 對比
ES5中設(shè)置參數(shù)默認(rèn)值的寫法
function animal(name, type) {
var name = name || 'yuan';
var type = type || 'monkey';
console.log(name, type);
}
這個寫法有個缺陷:參數(shù)傳遞進(jìn)來的布爾值必須為true攒霹,如果傳入的值為空字符串或者undefined 等這些轉(zhuǎn)換為false的參數(shù),則會影響結(jié)構(gòu)浆洗。所以,ES6為了彌補這個缺陷集峦,做了如下設(shè)置:
function animal(name = 'yuan', type = 'monkey') {
console.log(name, type);
}
2伏社、傳入?yún)?shù)類型對輸出結(jié)果的影響
function animal(name = 'yuan', type = 'monkey') {
console.log(name, type);
}
animal(); // yuan monkey
animal(name = 'dog'); // dog monkey
animal(name = 'yuan', undefined); // yuan monkey
animal(name = 'yuan', null); // yuan null
animal(false, undefined); // false "monkey"
animal(0, undefined); // 0 "monkey"
上面代碼4中調(diào)取函數(shù)的方式,只有不傳和傳入undefined 的會觸發(fā)默認(rèn)值塔淤,而傳入其它值或者null摘昌,則不會觸發(fā)默認(rèn)值。
3高蜂、注意參數(shù)放置位置
// 錯誤寫法
function animal(name = 'yuan', type) {
console.log(name, type);
}
// 正確寫法
function animal(name, type = 'monkey') {
console.log(name, type);
}
如上聪黎,在設(shè)置了默認(rèn)值的參數(shù)后,就不需要在設(shè)置其他參數(shù)了备恤,通常情況下稿饰,若有參數(shù)為默認(rèn)值時,一般是放在尾參數(shù)位置露泊。
4喉镰、參數(shù)默認(rèn)值與解構(gòu)賦值默認(rèn)值的結(jié)合使用
對比下面兩種寫法
// 第一種寫法,參數(shù)默認(rèn)值為空對象惭笑,解構(gòu)賦值有具體的默認(rèn)值
function method1({x = 0, y = 0} = {}) {
return [x, y];
}
// 第二種寫法侣姆,參數(shù)默認(rèn)值是一個具體的屬性對象,而對象解構(gòu)賦值沒有設(shè)置默認(rèn)值
function method2({x, y} = {x: 0, y: 0}) {
return [x, y];
}
// 函數(shù)沒有參數(shù)時
method1(); // [0, 0]
method2(); // [0, 0]
// x 和 y 都有值
method1({x: 2, y: 3}); // [2, 3]
method2({x: 2, y: 3}); // [2, 3]
// x 有值, y 沒有值
method1({x: 2}); // [2, 0]
method2({x: 2}); // [2, undefined]
// x 沒有值, y 有值
method1({y: 2}); // [0, 2]
method2({y: 2}); // [undefined, 2
// x 和 y 都沒有值
method1({}); // [0, 0]
method2({}); // [undefined, undefined]
5沉噩、使用參數(shù)默認(rèn)值對函數(shù)length 屬性的影響
(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
(function(a, ...b) {} ).length // 1
由上面代碼可以看出捺宗,函數(shù)的參數(shù)在指定默認(rèn)值之后,函數(shù)的length 屬性會失真川蒙,返回的length 值蚜厉,是沒有指定默認(rèn)值的參數(shù)的個數(shù),注意這里的length 也不包括rest參數(shù)(如第二點介紹)的個數(shù)派歌。
6弯囊、注意點
因函數(shù)參數(shù)是默認(rèn)聲明的,如果如果用let 或 const 重新聲明變量胶果,會報錯:
function animal(name = "yuan") {
let name = dog;
console.log(name);
}
animal(); // 報錯: Uncaught SyntaxError: Identifier 'name' has already been declared
二匾嘱、rest 參數(shù)
案例 呈現(xiàn)
// 求和,把結(jié)果賦值給 result
function sum(result, ...values) {
console.log(values); // [1, 2, 3, 4]早抠,這個變量返回的是一個數(shù)組
values.forEach( function(value, index) {
result += value;
})
console.log(result);
}
sum(11, 1, 2, 3, 4,); // 21
如上霎烙,rest參數(shù)(3個點 + 變量名)表示的是:獲取函數(shù)多余的參數(shù),且這個變量是一個數(shù)組。還有一點要注意的是rest參數(shù)必須是尾參數(shù)悬垃,后面不能加其他的參數(shù)游昼,否則會報錯:
// 錯誤寫法
function sum(res, ...values, another) {
console.log(values);
}
sum(); // 報錯:Uncaught SyntaxError: Rest parameter must be last formal parameter
三、name屬性
ES6中增加了函數(shù)的name屬性
const animal = function() {};
animal.name; // "animal"
Function 構(gòu)造函數(shù)會發(fā)的函數(shù)實例尝蠕,name 屬性的值為“anonymous”
(new Function).name; // "anonymous"
bind 返回的函數(shù)烘豌,name屬性值會加上“bound”前綴
function animal() {};
animal.bind({}).name; // "bound animal"
匿名函數(shù)的bind 返回的值“bound”
(function () {}).bind({}).name; // "bound"
四、箭頭函數(shù)
1看彼、定義
用箭頭“=>”來定義函數(shù)廊佩。
2、用法
對比
// ES5 寫法
var sum = function(a) {
return a;
}
// ES6 寫法
var sum = a => a;
如上代碼靖榕,在ES6中标锄,第一個a表示函數(shù)參數(shù),箭頭“=>”后面的 a 表示函數(shù)體茁计。
上述只是針對一個參數(shù)和函數(shù)體只有一條語句的寫法料皇,若函數(shù)參數(shù)的個數(shù)和函數(shù)體的語句超過1個要如何表示呢?如下:
var sum = (a, b) => { return a + b};
sum(1,4); // 5
如上星压,若函數(shù)的參數(shù)個數(shù)超過一個時践剂,需要用圓括號“()”來代表參數(shù),函數(shù)體的語句條數(shù)超過一條時租幕,需要用大括號將它們括起來舷手。
當(dāng)函數(shù)體中返回的是對象時,我們需要將其用圓括號“()”括起來:
var person = name => ({ name: 'yuan', type: 'monkey'});
3劲绪、使用注意點
(1)男窟、函數(shù)體內(nèi)的 this 指向,指向的是定義時所在的對象贾富,而不是使用時所在的對象歉眷。
在箭頭函數(shù)中 this 指向是固定的:
function foo() {
setTimeout( () => {
console.log('id:', this.id)
}, 100);
}
var id = 21;
foo.call({ id: 42}); // 42
如上輸出結(jié)果,此處的this 指向并不是全局對象 window颤枪,因為在箭頭函數(shù)中汗捡,this 總是指向函數(shù)定義生效時所在的對象,所以輸出的結(jié)果是 42畏纲。
如果還不清楚箭頭函數(shù) this 指向的含義扇住,我們可以這樣通俗的理解:在JavaScript 中每一個 function 都有一個獨立的運行上下文,而箭頭函數(shù)不是一個普通的 function 盗胀,沒有自己的運行上下文艘蹋。所以在箭頭函數(shù)中寫的 this,具體指的是包含這個箭頭函數(shù)最近的 function 的上下文中的 this票灰,如果沒有最近的 function女阀,this 指向的是全局宅荤。
(2)、不能當(dāng)做構(gòu)造函數(shù)用浸策,即不能使用 new 命令冯键,否則會報錯
(3),、不可以使用arguments 對象庸汗,該對象哎函數(shù)體內(nèi)不存在惫确。如果要用,使用 rest 參數(shù)代替
(4)蚯舱、不能使用 yield 命令雕薪,因為箭頭函數(shù)不能用作Generator 函數(shù)
六、函數(shù)的尾調(diào)用
1晓淀、定義
尾調(diào)用是函數(shù)式編程的一個重要概念,是指某個函數(shù)的最后一步調(diào)用另一個函數(shù)盏档。
function f(x) {
return g(x);
}
函數(shù)f 的最后一步是調(diào)用函數(shù)g凶掰,這就是尾調(diào)用。
2蜈亩、尾遞歸
函數(shù)調(diào)用自身叫做遞歸懦窘,如果尾調(diào)用自身就是尾遞歸。
function factorial(n) {
if(n === 1) return 1;
return n * factorial(n - 1);
}
factorial(5); // 120
在ES6 中只要使用尾遞歸稚配,就不會發(fā)生棧溢出畅涂,相對節(jié)省內(nèi)存。
3道川、尾遞歸改寫
為了確保最后一步只調(diào)用自身午衰,需要對尾遞歸函數(shù)進(jìn)行改寫,把所有用到的內(nèi)部變量改寫成函數(shù)的參數(shù)冒萄。
使用柯里化函數(shù)編程思想臊岸,將多參數(shù)的函數(shù)轉(zhuǎn)換成單參數(shù)的形式:
function curring(fn, n) {
return function (m) {
return fn.call(this, m, n);
}
}
function tailFactorial(n, total) {
if(n === 1) return total;
return tailFactorial(n - 1, n * total);
}
const factorial = curring(tailFactorial, 1);
factorial(5); // 120
采用ES6的函數(shù)默認(rèn)值改寫:
function factorial(n, total = 1) {
if(n === 1) return total;
return factorial(n - 1, n * total);
}
factorial(5); // 120
在尾調(diào)用優(yōu)化時,循環(huán)是可以用遞歸代替的尊流,而一旦使用遞歸帅戒,就最好使用尾遞歸。
五崖技、總結(jié)
1逻住、本章需要掌握ES6中函數(shù)的表示方式,以及 rest 參數(shù)的使用迎献。
2瞎访、本章重點:箭頭函數(shù)的表示方法,以箭頭函數(shù)使用的注意事項忿晕,特別是箭頭函數(shù)中 this 的指向問題装诡。
章節(jié)目錄
1银受、ES6中啥是塊級作用域?運用在哪些地方鸦采?
2宾巍、ES6中使用解構(gòu)賦值能帶給我們什么?
3渔伯、ES6字符串?dāng)U展增加了哪些顶霞?
4、ES6對正則做了哪些擴(kuò)展锣吼?
5选浑、ES6數(shù)值多了哪些擴(kuò)展?
6玄叠、ES6函數(shù)擴(kuò)展(箭頭函數(shù))
7古徒、ES6 數(shù)組給我們帶來哪些操作便利?
8读恃、ES6 對象擴(kuò)展
9隧膘、Symbol 數(shù)據(jù)類型在 ES6 中起什么作用?
10寺惫、Map 和 Set 兩數(shù)據(jù)結(jié)構(gòu)在ES6的作用
11疹吃、ES6 中的Proxy 和 Reflect 到底是什么鬼?
12西雀、從 Promise 開始踏入異步操作之旅
13萨驶、ES6 迭代器(Iterator)和 for...of循環(huán)使用方法
14、ES6 異步進(jìn)階第二步:Generator 函數(shù)
15艇肴、JavaScript 異步操作進(jìn)階第三步:async 函數(shù)
16腔呜、ES6 構(gòu)造函數(shù)語法糖:class 類