1.箭頭函數(shù)
ES6新增屬性。箭頭函數(shù)特別適合嵌入函數(shù)的場(chǎng)景。
//只有一個(gè)參數(shù),括號(hào)可以省略
let double = x => {return 2 * x};
let tripble = (x) => {return 2 * x};
//沒(méi)有參數(shù)需要括號(hào)
let getRandom = () => {return Math.random();};
//有多個(gè)參數(shù)需要括號(hào)
let sum = (a, b) => {return a + b}
/**
* 箭頭函數(shù)也可以不使用大括號(hào),但這會(huì)改變函數(shù)的行為。如果不使用大括號(hào)
* 那么箭頭后面就只能有一行代碼(賦值操作或者表達(dá)式),而且省略大括號(hào)
* 會(huì)隱式返回這行代碼的值。
*/
let fun1 = (x) => {return 2 * x;}
let fun2 = (x) => 2 * x; //等于上面的寫(xiě)法
let fun3 = (x) => return 2 * x ; //無(wú)效寫(xiě)法
箭頭函數(shù)雖然語(yǔ)法簡(jiǎn)介,但是很多場(chǎng)合不適用。箭頭函數(shù)不能使用arguments、super、new.target,也不能用作構(gòu)造函數(shù)。箭頭函數(shù)也沒(méi)有protptype屬性。
2.函數(shù)名
因?yàn)楹瘮?shù)名就是指向函數(shù)的指針,所以它們跟其他包含對(duì)象指針的變量具有相同的行為。
在ES6中,所有的函數(shù)對(duì)象都會(huì)暴露一個(gè)只讀的name屬性,其中包含關(guān)于函數(shù)的信息。
function sum(num1, num2) { return num1 + num2; }
console.log(sum(1,2)); //3
let anotherSum = sum;
sum = null;
console.log(anotherSum(1,2)); //3
console.log(anotherSum.name) //sum 返回的是方法名
anotherSum.name = '小馬哥';
console.log(anotherSum.name) //sum name屬性只讀,不能修改
3.理解參數(shù)
ECMAScript函數(shù)即不關(guān)心傳入的參數(shù)個(gè)數(shù),也不關(guān)心這些參數(shù)的數(shù)據(jù)類(lèi)型。定義函數(shù)時(shí)要接收2個(gè)參數(shù),并不意味著調(diào)用的時(shí)候就要傳入2個(gè)參數(shù),可以傳1個(gè),3個(gè)甚至一個(gè)都不傳。事實(shí)上,在使用function關(guān)鍵字定義(非箭頭)函數(shù)時(shí),可以在函數(shù)的內(nèi)部訪問(wèn)arguments對(duì)象,從中獲取傳進(jìn)來(lái)的每個(gè)參數(shù)值。arguments是一個(gè)類(lèi)數(shù)組對(duì)象(不是Array的實(shí)例)
function sayHi(name, message) {
console.log(arguments.length); //2
return '小馬哥對(duì)' + name + '說(shuō)' + message;
}
function sayHello() {
console.log(arguments.length); //2
return '小馬哥對(duì)' + arguments[0] + '說(shuō)' + arguments[1];
}
let sayHello2 = () => {
return '小馬哥對(duì)' + arguments[0] + '說(shuō)' + arguments[1];
}
console.log(sayHi('韓梅梅', '今天加班')) //小馬哥對(duì)韓梅梅說(shuō)今天加班
console.log(sayHello('韓梅梅', '今天加班')) //小馬哥對(duì)韓梅梅說(shuō)今天加班
console.log(sayHello2('韓梅梅', '今天加班')) //報(bào)錯(cuò)
箭頭函數(shù)中的參數(shù):如果函數(shù)是使用箭頭函數(shù)語(yǔ)法定義的,那么傳給函數(shù)的參數(shù)不能使用arguments關(guān)鍵字訪問(wèn),而只能通過(guò)定義的命名參數(shù)訪問(wèn)。
function foo(){
let sayHello = () => {
console.log( '小馬哥對(duì)' + arguments[0] + '說(shuō)' + arguments[1]); //小馬哥對(duì)韓梅梅說(shuō)今天加班
}
sayHello();
}
foo('李雷','你也加班');
4.沒(méi)有重載
ECMAScript函數(shù)如果定義了同名函數(shù),則后面定義的會(huì)覆蓋先定義的。
5.默認(rèn)參數(shù)值
在ECMAScript5.1及以前,實(shí)現(xiàn)默認(rèn)參數(shù)的一種常用方式就是檢測(cè)某個(gè)參數(shù)是否等于undefined。在ES6開(kāi)始可以支持顯示定義默認(rèn)參數(shù)。
function sayName(name = '小馬哥') {
console.log('myName==' + name);
}
sayName('孫紅雷'); //myName==孫紅雷
sayName(); //myName==小馬哥
6.參數(shù)擴(kuò)展與收集
ES6新增了擴(kuò)展操作符,使用它可以非常簡(jiǎn)潔地操作和組合數(shù)據(jù)。擴(kuò)展操作符最有用的場(chǎng)景就是函數(shù)定義中的參數(shù)列表。
- 6.1擴(kuò)展參數(shù):對(duì)于可迭代對(duì)象應(yīng)用擴(kuò)展操作符,并將其作為一個(gè)參數(shù)傳入,可以將可迭代對(duì)象拆分,并將返回的每個(gè)值單獨(dú)傳入。
let values = [1, 2, 3, 4]
function getSum() {
let sum = 0;
for (let i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
console.log(getSum.apply(null, values)); //10---es5寫(xiě)法
console.log(getSum(-1,...values,5)); //14
console.log(getSum(...values,5,6,7,8,9,10));//55
console.log(getSum(...values,...[5,6,7,8,9,10]));//55
console.log(getSum(5,...values,...[5,6,7,8,9,10]));//60
- 6.2收集參數(shù): 在構(gòu)思函數(shù)定義時(shí),可以使用擴(kuò)展操作符把不同長(zhǎng)度的獨(dú)立參數(shù)組合為一個(gè)數(shù)組。類(lèi)似于arguments對(duì)象的構(gòu)造機(jī)制,只不過(guò)收集參數(shù)的結(jié)果會(huì)得到一個(gè)Array實(shí)例。
let ignorFirst = (firstValue, ...values) => {
console.log(values);
}
ignorFirst() // []
ignorFirst(1,2,3,4,5) //[2, 3, 4, 5]
7.函數(shù)內(nèi)部(arguments,this,new.target)
- arguments對(duì)象:這個(gè)對(duì)象只有以function關(guān)鍵字定義函數(shù)時(shí)候才會(huì)有,主要用于包含函數(shù)參數(shù)。arguments還有一個(gè)callee屬性,是指向arguments對(duì)象所在函數(shù)的指針。
function factorial(num) {
if (num <= 1) {
return 1;
} else {
return num * arguments.callee(num - 1); //指向當(dāng)前對(duì)象所在的函數(shù)
}
}
let trueFactorial = factorial;
factorial = function () {
return 0;
}
console.log(trueFactorial(5)) //120
console.log(factorial(5)) //0
-
this對(duì)象:在標(biāo)注函數(shù)(指向調(diào)用該函數(shù)的上下文)和箭頭函數(shù)中(指向定義該函數(shù)的上下文)有不同的行為。
在標(biāo)準(zhǔn)函數(shù)中:this引用的是把函數(shù)當(dāng)成方法調(diào)用的上下文對(duì)象,通常這個(gè)時(shí)候,稱(chēng)其為this值(在網(wǎng)頁(yè)的全局上下文中調(diào)用函數(shù)時(shí),this指向windows)。
window.color = 'red';
let o = {
color: 'blue',
}
function sayColor() {
console.log(this.color);
}
sayColor() //red
o.sayColor = sayColor;
//調(diào)用的時(shí)候,函數(shù)調(diào)用者變更為o,this指向o
o.sayColor(); //blue
在箭頭函數(shù)中:this引用的是定義箭頭函數(shù)的上下文,在事件回調(diào)或者定時(shí)回調(diào)中調(diào)用某個(gè)函數(shù),this指向的并非想要的對(duì)象。此時(shí)將回調(diào)函數(shù)寫(xiě)成箭頭函數(shù)就可以解決這個(gè)問(wèn)題。因?yàn)榧^函數(shù)中的this會(huì)保留定義該函數(shù)時(shí)的上下文。
window.color = 'red';
let o = {
color: 'blue',
}
let sayColor = () => console.log(this.color);
sayColor() //red
o.sayColor = sayColor;
o.sayColor(); //red
- caller屬性:這個(gè)屬性引用的是調(diào)用當(dāng)前函數(shù)的函數(shù),或者如果的在全局作用域中調(diào)用的則為null。
function outer(){
let arr =[];
for (let i=0;i<20;i++){
arr[i] = i;
}
inner();
}
function inner(){
let arr =[];
for (let i=0;i<20;i++){
arr[i] = i;
}
console.log(inner.caller) //outer的源代碼
console.log(arguments.callee.caller) //等價(jià)于上面
}
outer();
- new.target屬性(ES6新增): 檢測(cè)函數(shù)是否使用new關(guān)鍵字調(diào)用的new.target屬性。如果函數(shù)是正常調(diào)用的則new.target的值是undefined,反之將引用被調(diào)用的構(gòu)造函數(shù)。
8.函數(shù)屬性與方法(length,prototype,apply(),call())
- length:表示該函數(shù)方法的入?yún)€(gè)數(shù)。
- prototype:保存引用類(lèi)型所有實(shí)例方法的地方,就意味著toString()、valueOf()等方法都保存在prototype上,進(jìn)而由所有實(shí)例共享。在ES5中,prototype屬性是不可枚舉的,因此使用for-in循環(huán)不會(huì)返回這個(gè)屬性。
- apply():這個(gè)方法都會(huì)以指定的this值來(lái)調(diào)用函數(shù),即會(huì)設(shè)置調(diào)用函數(shù)時(shí)函數(shù)體內(nèi)的this對(duì)象的值。apply()接收兩個(gè)參數(shù):函數(shù)體內(nèi)this的值和一個(gè)參數(shù)數(shù)組。第二個(gè)參數(shù)可以是Array的實(shí)例,但也可以是arguments對(duì)象。
- call():方法作用和apply()一樣,只是傳參的形式不同,第一個(gè)參數(shù)是this,后面的參數(shù)必須一個(gè)一個(gè)列出來(lái)。
function sum(num1,num2){
return num1 + num2;
}
function sum2(num1,num2){
return sum.apply(this,arguments)
}
function sum3(num1,num2){
return sum.call(this,num1,num2);
}
console.log(sum2(20,30)); //50
console.log(sum3(20,30)); //50
apply()和call(),更重要的作用是控制函數(shù)調(diào)用上下文,即函數(shù)體內(nèi)this值的能力。
window.color = 'red';
let o = {
color: 'blue'
};
function sayColor() {
console.log(this.color);
}
sayColor(); //red
sayColor.call(this); //red
sayColor.apply(window); //red
sayColor.apply(o); //blue
sayColor.call(o); //blue
9.閉包
匿名函數(shù)經(jīng)常被人誤以為是閉包。閉包指的是那些引用了另一個(gè)函數(shù)作用域變量的函數(shù),通常是在嵌套函數(shù)中實(shí)現(xiàn)的。
function compare(propertyName) {
return function (object1, object2) {
//內(nèi)部函數(shù)(匿名函數(shù))引用了外部函數(shù)的變量propertyName
let value1 = object1[propertyName];
let value2 = object2[propertyName];
return value1 === value2 ? 0 : value1 > value2 ? 1 : -1;
}
}
在這個(gè)內(nèi)部函數(shù)被返回并在其他地方被使用后,它仍然引用著哪個(gè)變量。因?yàn)檫@是因?yàn)閮?nèi)部函數(shù)的作用域鏈包含compare()函數(shù)的作用域。
10.this 對(duì)象
在閉包中使用this會(huì)讓代碼變復(fù)雜。如果內(nèi)部函數(shù)沒(méi)有使用箭頭函數(shù)定義,則this對(duì)象會(huì)在運(yùn)行時(shí)綁定到執(zhí)行函數(shù)的上下文。如果在全局函數(shù)中調(diào)用,非嚴(yán)格模式下,this等于window。
window.identity = 'The Window';
let object = {
identity: 'My Object',
getIdentityFunc() {
return function () {
return this.identity;
}
}
}
console.log(object.getIdentityFunc()()) //The Window
object.getIdentityFunc()返回函數(shù),所以object.getIdentityFunc()()立即調(diào)用返回的函數(shù),從而得到一個(gè)字符串。每個(gè)函數(shù)在被調(diào)用的時(shí)候都會(huì)創(chuàng)建兩個(gè)特殊的變量:this和arguments。內(nèi)部函數(shù)用于不可能直接(可以間接,箭頭函數(shù)或者使用變量)訪問(wèn)外部函數(shù)的這兩個(gè)變量。
11.立即調(diào)用的函數(shù)表達(dá)式
立即調(diào)用的函數(shù)表達(dá)式又稱(chēng)為立即嗲用的函數(shù)表達(dá)式(IIFE)。類(lèi)似于函數(shù)聲明,但是由于被包含在括號(hào)中,所以會(huì)被解釋為函數(shù)表達(dá)式。緊跟在第一組括號(hào)后面的第二組括號(hào)會(huì)立即調(diào)用前面的函數(shù)表達(dá)式。在ES5.1及以前,為了防止變量定義外泄,IIFE是個(gè)非常有效的方式。也不會(huì)導(dǎo)致閉包相關(guān)的內(nèi)存問(wèn)題,因?yàn)椴淮嬖趯?duì)這個(gè)函數(shù)的引用,為此,只要函數(shù)執(zhí)行完畢,其作作用域鏈就可以被銷(xiāo)毀。
(function () {
//塊級(jí)作用域
})();