1.箭頭函數(shù)
ES6新增屬性浇坐。箭頭函數(shù)特別適合嵌入函數(shù)的場景睬捶。
//只有一個參數(shù),括號可以省略
let double = x => {return 2 * x};
let tripble = (x) => {return 2 * x};
//沒有參數(shù)需要括號
let getRandom = () => {return Math.random();};
//有多個參數(shù)需要括號
let sum = (a, b) => {return a + b}
/**
* 箭頭函數(shù)也可以不使用大括號,但這會改變函數(shù)的行為近刘。如果不使用大括號
* 那么箭頭后面就只能有一行代碼(賦值操作或者表達式)擒贸,而且省略大括號
* 會隱式返回這行代碼的值。
*/
let fun1 = (x) => {return 2 * x;}
let fun2 = (x) => 2 * x; //等于上面的寫法
let fun3 = (x) => return 2 * x ; //無效寫法
箭頭函數(shù)雖然語法簡介觉渴,但是很多場合不適用介劫。箭頭函數(shù)不能使用arguments、super疆拘、new.target蜕猫,也不能用作構(gòu)造函數(shù)。箭頭函數(shù)也沒有protptype屬性哎迄。
2.函數(shù)名
因為函數(shù)名就是指向函數(shù)的指針回右,所以它們跟其他包含對象指針的變量具有相同的行為。
在ES6中漱挚,所有的函數(shù)對象都會暴露一個只讀的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ù)個數(shù)蹬屹,也不關(guān)心這些參數(shù)的數(shù)據(jù)類型。定義函數(shù)時要接收2個參數(shù)白华,并不意味著調(diào)用的時候就要傳入2個參數(shù)慨默,可以傳1個,3個甚至一個都不傳弧腥。事實上厦取,在使用function關(guān)鍵字定義(非箭頭)函數(shù)時,可以在函數(shù)的內(nèi)部訪問arguments對象管搪,從中獲取傳進來的每個參數(shù)值虾攻。arguments是一個類數(shù)組對象(不是Array的實例)
function sayHi(name, message) {
console.log(arguments.length); //2
return '小馬哥對' + name + '說' + message;
}
function sayHello() {
console.log(arguments.length); //2
return '小馬哥對' + arguments[0] + '說' + arguments[1];
}
let sayHello2 = () => {
return '小馬哥對' + arguments[0] + '說' + arguments[1];
}
console.log(sayHi('韓梅梅', '今天加班')) //小馬哥對韓梅梅說今天加班
console.log(sayHello('韓梅梅', '今天加班')) //小馬哥對韓梅梅說今天加班
console.log(sayHello2('韓梅梅', '今天加班')) //報錯
箭頭函數(shù)中的參數(shù):如果函數(shù)是使用箭頭函數(shù)語法定義的铡买,那么傳給函數(shù)的參數(shù)不能使用arguments關(guān)鍵字訪問,而只能通過定義的命名參數(shù)訪問霎箍。
function foo(){
let sayHello = () => {
console.log( '小馬哥對' + arguments[0] + '說' + arguments[1]); //小馬哥對韓梅梅說今天加班
}
sayHello();
}
foo('李雷','你也加班');
4.沒有重載
ECMAScript函數(shù)如果定義了同名函數(shù)奇钞,則后面定義的會覆蓋先定義的。
5.默認參數(shù)值
在ECMAScript5.1及以前漂坏,實現(xiàn)默認參數(shù)的一種常用方式就是檢測某個參數(shù)是否等于undefined景埃。在ES6開始可以支持顯示定義默認參數(shù)。
function sayName(name = '小馬哥') {
console.log('myName==' + name);
}
sayName('孫紅雷'); //myName==孫紅雷
sayName(); //myName==小馬哥
6.參數(shù)擴展與收集
ES6新增了擴展操作符樊拓,使用它可以非常簡潔地操作和組合數(shù)據(jù)纠亚。擴展操作符最有用的場景就是函數(shù)定義中的參數(shù)列表。
- 6.1擴展參數(shù):對于可迭代對象應(yīng)用擴展操作符筋夏,并將其作為一個參數(shù)傳入蒂胞,可以將可迭代對象拆分,并將返回的每個值單獨傳入条篷。
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寫法
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ù)組合為一個數(shù)組。類似于arguments對象的構(gòu)造機制赴叹,只不過收集參數(shù)的結(jié)果會得到一個Array實例鸿染。
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對象:這個對象只有以function關(guān)鍵字定義函數(shù)時候才會有,主要用于包含函數(shù)參數(shù)乞巧。arguments還有一個callee屬性涨椒,是指向arguments對象所在函數(shù)的指針。
function factorial(num) {
if (num <= 1) {
return 1;
} else {
return num * arguments.callee(num - 1); //指向當(dāng)前對象所在的函數(shù)
}
}
let trueFactorial = factorial;
factorial = function () {
return 0;
}
console.log(trueFactorial(5)) //120
console.log(factorial(5)) //0
-
this對象:在標(biāo)注函數(shù)(指向調(diào)用該函數(shù)的上下文)和箭頭函數(shù)中(指向定義該函數(shù)的上下文)有不同的行為绽媒。
在標(biāo)準(zhǔn)函數(shù)中:this引用的是把函數(shù)當(dāng)成方法調(diào)用的上下文對象蚕冬,通常這個時候,稱其為this值(在網(wǎng)頁的全局上下文中調(diào)用函數(shù)時是辕,this指向windows)囤热。
window.color = 'red';
let o = {
color: 'blue',
}
function sayColor() {
console.log(this.color);
}
sayColor() //red
o.sayColor = sayColor;
//調(diào)用的時候,函數(shù)調(diào)用者變更為o,this指向o
o.sayColor(); //blue
在箭頭函數(shù)中:this引用的是定義箭頭函數(shù)的上下文获三,在事件回調(diào)或者定時回調(diào)中調(diào)用某個函數(shù)旁蔼,this指向的并非想要的對象。此時將回調(diào)函數(shù)寫成箭頭函數(shù)就可以解決這個問題疙教。因為箭頭函數(shù)中的this會保留定義該函數(shù)時的上下文棺聊。
window.color = 'red';
let o = {
color: 'blue',
}
let sayColor = () => console.log(this.color);
sayColor() //red
o.sayColor = sayColor;
o.sayColor(); //red
- caller屬性:這個屬性引用的是調(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) //等價于上面
}
outer();
- new.target屬性(ES6新增): 檢測函數(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)€數(shù)耐亏。
- prototype:保存引用類型所有實例方法的地方,就意味著toString()沪斟、valueOf()等方法都保存在prototype上广辰,進而由所有實例共享。在ES5中主之,prototype屬性是不可枚舉的择吊,因此使用for-in循環(huán)不會返回這個屬性。
- apply():這個方法都會以指定的this值來調(diào)用函數(shù)槽奕,即會設(shè)置調(diào)用函數(shù)時函數(shù)體內(nèi)的this對象的值几睛。apply()接收兩個參數(shù):函數(shù)體內(nèi)this的值和一個參數(shù)數(shù)組。第二個參數(shù)可以是Array的實例粤攒,但也可以是arguments對象所森。
- call():方法作用和apply()一樣,只是傳參的形式不同夯接,第一個參數(shù)是this焕济,后面的參數(shù)必須一個一個列出來。
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)常被人誤以為是閉包逊拍。閉包指的是那些引用了另一個函數(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;
}
}
在這個內(nèi)部函數(shù)被返回并在其他地方被使用后顺献,它仍然引用著哪個變量旗国。因為這是因為內(nèi)部函數(shù)的作用域鏈包含compare()函數(shù)的作用域。
10.this 對象
在閉包中使用this會讓代碼變復(fù)雜注整。如果內(nèi)部函數(shù)沒有使用箭頭函數(shù)定義能曾,則this對象會在運行時綁定到執(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ù)驼唱,從而得到一個字符串。每個函數(shù)在被調(diào)用的時候都會創(chuàng)建兩個特殊的變量:this和arguments驹暑。內(nèi)部函數(shù)用于不可能直接(可以間接玫恳,箭頭函數(shù)或者使用變量)訪問外部函數(shù)的這兩個變量辨赐。
11.立即調(diào)用的函數(shù)表達式
立即調(diào)用的函數(shù)表達式又稱為立即嗲用的函數(shù)表達式(IIFE)。類似于函數(shù)聲明京办,但是由于被包含在括號中掀序,所以會被解釋為函數(shù)表達式。緊跟在第一組括號后面的第二組括號會立即調(diào)用前面的函數(shù)表達式惭婿。在ES5.1及以前不恭,為了防止變量定義外泄,IIFE是個非常有效的方式财饥。也不會導(dǎo)致閉包相關(guān)的內(nèi)存問題换吧,因為不存在對這個函數(shù)的引用,為此钥星,只要函數(shù)執(zhí)行完畢沾瓦,其作作用域鏈就可以被銷毀。
(function () {
//塊級作用域
})();