ES6標(biāo)準(zhǔn) Arrow Function(箭頭函數(shù)=>)

2020-05-18 10:47:08 來(lái)源:互聯(lián)網(wǎng)作者:廖雪峰 人氣: 次閱讀 48 條評(píng)論

ES6標(biāo)準(zhǔn)新增了一種新的函數(shù):Arrow Function(箭頭函數(shù)),為什么叫Arrow Function?因?yàn)樗亩x用的就是一個(gè)箭頭ES6—箭頭函數(shù)0.為什么會(huì)出現(xiàn)箭頭函數(shù)?1.傳統(tǒng)的javascript函數(shù)...

ES6標(biāo)準(zhǔn)新增了一種新的函數(shù):Arrow Function(箭頭函數(shù)),為什么叫Arrow Function?因?yàn)樗亩x用的就是一個(gè)箭頭

ES6—箭頭函數(shù)

0.為什么會(huì)出現(xiàn)箭頭函數(shù)?

1.傳統(tǒng)的javascript函數(shù)語(yǔ)法并沒(méi)有提供任何的靈活性,每一次你需要定義一個(gè)函數(shù)時(shí),你都必須輸入function () {},這至少會(huì)出現(xiàn)兩個(gè)問(wèn)題,ES6箭頭函數(shù)都圓滿解決了它,

第一個(gè)問(wèn)題:代碼輸入快了容易輸錯(cuò)成 funciton或者functoin或者其它,但是=>這個(gè)玩意你要是再寫錯(cuò)就只能說(shuō)有點(diǎn)過(guò)分了。

第二個(gè)問(wèn)題:節(jié)省大量代碼,我們先不用管下面的ES6代碼為什么這樣的語(yǔ)法能實(shí)現(xiàn)同樣的功能,我們就直觀的感受一下代碼量。

ES5寫法:

function addFive(num){
   return num+5; 
}
alert(addFive(10));

ES6寫法:

var addFive = num=>num+5;
alert(addFive(5));

沒(méi)有function、沒(méi)有return,沒(méi)有(),沒(méi)有{},這些全變成了浮云,世界好清靜。

從上面我們就可以看到,使用箭頭函數(shù)不僅僅能夠避免錯(cuò)誤,同時(shí)還能讓我們少一丟丟代碼,當(dāng)然實(shí)際工作中遠(yuǎn)比這個(gè)代碼量節(jié)省更多。
一方面是因?yàn)榉e累效應(yīng),每一部分少一丟丟合起來(lái)就多了,一方面是它還有更能節(jié)省代碼和大幅提高工作效率的場(chǎng)景。

接下來(lái)我們就說(shuō)說(shuō)今天的主角--箭頭函數(shù)。

ES6標(biāo)準(zhǔn)新增了一種新的函數(shù):Arrow Function(箭頭函數(shù)),也稱“胖箭頭函數(shù)”, 允許

使用“箭頭”(=>)定義函數(shù),是一種簡(jiǎn)寫的函數(shù)表達(dá)式。

1、箭頭函數(shù)語(yǔ)法

在ES5中我們實(shí)現(xiàn)一個(gè)求和的函數(shù):

var sum = function(x, y) {
  return x + y
}

要使用箭頭函數(shù),可以分兩步實(shí)現(xiàn)同樣的函數(shù)功能:

首先使用=>來(lái)替代關(guān)鍵詞function

var sum = (x, y) => {
  return x + y
}

這個(gè)特性非常好?。?!

前面我們已經(jīng)說(shuō)過(guò)用=>來(lái)替代關(guān)鍵詞function就意味著不會(huì)寫錯(cuò)function了,這真是一個(gè)絕妙的設(shè)計(jì)思想!

其次,函數(shù)體只有一條返回語(yǔ)句時(shí), 我們可以省略括號(hào){}和return關(guān)鍵詞:

var sum = (x, y) => x + y

再夸張一點(diǎn)點(diǎn),如果只有一個(gè)參數(shù)時(shí),()可省略。

這是箭頭函數(shù)最簡(jiǎn)潔的形式,常用于作用簡(jiǎn)單的處理函數(shù),比如過(guò)濾:

// ES5
var array = ['1', '2345', '567', '89'];
array = array.filter(function (item) {
  return item.length > 2;
});
// ["2345", "567"]
 
 
// ES6
let array = ['1', '2345', '567', '89'];
array = array.filter(item => item.length > 2); 
// ["2345", "567"]

箭頭函數(shù)的主要使用模式如下:

// 一個(gè)參數(shù)對(duì)應(yīng)一個(gè)表達(dá)式
param => expression;// 例如 x => x+2;
 
// 多個(gè)參數(shù)對(duì)應(yīng)一個(gè)表達(dá)式
(param [, param]) => expression; //例如 (x,y) => (x + y);
 
// 一個(gè)參數(shù)對(duì)應(yīng)多個(gè)表示式
param => {statements;} //例如 x = > { x++; return x;};
 
// 多個(gè)參數(shù)對(duì)應(yīng)多個(gè)表達(dá)式
([param] [, param]) => {statements} // 例如 (x,y) => { x++;y++;return x*y;};
 
//表達(dá)式里沒(méi)有參數(shù)
() => expression; //例如var flag = (() => 2)(); flag等于2
 
() => {statements;} //例如 var flag = (() => {return 1;})(); flag就等于1
 
 //傳入一個(gè)表達(dá)式,返回一個(gè)對(duì)象
([param]) => ({ key: value });
//例如 var fuc = (x) => ({key:x})
    var object = fuc(1);
    alert(object);//{key:1}

大家不要覺(jué)得好多啊,好麻煩,其實(shí)這些根本不復(fù)雜。投入一次,受益終生。(怎么感覺(jué)我像賣保險(xiǎn)的……),寫一兩次你就習(xí)慣新的寫法了。

2、箭頭函數(shù)中的 this

箭頭函數(shù)內(nèi)的this值繼承自外圍作用域。運(yùn)行時(shí)它會(huì)首先到它的父作用域找,如果父作用域還是箭頭函數(shù),那么接著向上找,直到找到我們要的this指向。

我們先看一道經(jīng)典的關(guān)于this的面試題:

var name = 'leo';
var teacher = {
  name: "大彬哥",
  showName: function () {
    function showTest() {
      alert(this.name);
    }
    showTest();
  }
};
teacher.showName();//結(jié)果是 leo,而我們期待的是大彬哥,這里this指向了window,我們期待指向teacher

大家知道,ES5中的this說(shuō)好聽(tīng)了叫"靈活",說(shuō)不好聽(tīng)就是瞎搞,特別容易出問(wèn)題.而且面試還非常愛(ài)考,工作更不用說(shuō)了,經(jīng)常給我們開發(fā)搗亂,出現(xiàn)不好調(diào)試的bug,用E箭頭函數(shù)解決這個(gè)問(wèn)題就很得心應(yīng)手了。

var name = 'leo';
var teacher = {
  name: "大彬哥",
  showName: function () {
    let showTest = ()=>alert(this.name);
    showTest();
  }
};
teacher.showName();

箭頭函數(shù)中的this其實(shí)是父級(jí)作用域中的this。箭頭函數(shù)引用了父級(jí)的變量詞法作用域就是一個(gè)變量的作用在定義的時(shí)候就已經(jīng)被定義好,當(dāng)在本作用域中找不到變量,就會(huì)一直向父作用域中查找,直到找到為止。

由于this在箭頭函數(shù)中已經(jīng)按照詞法作用域綁定了,所以,用call或者apply調(diào)用箭頭函數(shù)時(shí),無(wú)法對(duì)this進(jìn)行綁定,即傳入的第一個(gè)參數(shù)被忽略:

var obj = {
  birth: 1996,
  getAge: function (year) {
    var b = this.birth; // 1996
    var fn = (y) => y - this.birth; // this.birth仍是1996
    return fn.call({birth:1990}, year);
  }
};
obj.getAge(2018); // 22 ( 2018 - 1996)
由于this已經(jīng)在詞法層面完成了綁定,通過(guò)call或apply方法調(diào)用一個(gè)函數(shù)時(shí),只是傳入了參數(shù)而已,對(duì)this并沒(méi)有什么影響 。因此,這個(gè)設(shè)計(jì)節(jié)省了開發(fā)者思考上下文綁定的時(shí)間。

3、箭頭函數(shù)的特性

3.1 箭頭函數(shù)沒(méi)有 arguments

箭頭函數(shù)不僅沒(méi)有this,常用的arguments也沒(méi)有。如果你能獲取到arguments,那它

一定是來(lái)自父作用域的。
function foo() {
 return () => console.log(arguments)
}
 
foo(1, 2)(3, 4) // 1,2

上例中如果箭頭函數(shù)有arguments,就應(yīng)該輸出的是3,4而不是1,2。

箭頭函數(shù)不綁定arguments,取而代之用rest參數(shù)…解決

var foo = (...args) => {
 return args
}
 
console.log(foo(1,3,56,36,634,6))  // [1, 3, 56, 36, 634, 6]

箭頭函數(shù)要實(shí)現(xiàn)類似純函數(shù)的效果,必須剔除外部狀態(tài)。我們可以看出,箭頭函數(shù)除了傳入的參數(shù)之外,真的在普通函數(shù)里常見(jiàn)的this、arguments、caller是統(tǒng)統(tǒng)沒(méi)有的!

如果你在箭頭函數(shù)引用了this、arguments或者參數(shù)之外的變量,那它們一定不是箭頭函數(shù)本身包含的,而是從父級(jí)作用域繼承的。

3.2 箭頭函數(shù)中不能使用 new

  this.name = name;
};
let one = new Person("galler");

運(yùn)行該程序,則出現(xiàn)TypeError: Person is not a constructor

3.3 箭頭函數(shù)可以與變量解構(gòu)結(jié)合使用。

const full = ({ first, last }) => first + ' ' + last;
 
// 等同于
function full(person) {
 return person.first + ' ' + person.last;
}
 
 full({first: 1, last: 5}) // '1 5'

3.4 箭頭函數(shù)沒(méi)有原型屬性

var foo = () => {};
console.log(foo.prototype) //undefined

由此可以看出箭頭函數(shù)沒(méi)有原型。

另一個(gè)錯(cuò)誤是在原型上使用箭頭函數(shù),如:

function A() {
?this.foo = 1
}
?
A.prototype.bar = () => console.log(this.foo)
?
let a = new A()
a.bar() //undefined

同樣,箭頭函數(shù)中的this不是指向A,而是根據(jù)變量查找規(guī)則回溯到了全局作用域。同樣,使用普通函數(shù)就不存在問(wèn)題。箭頭函數(shù)中不可加new,也就是說(shuō)箭頭函數(shù)不能當(dāng)構(gòu)造函數(shù)進(jìn)行使用。

3.5 箭頭函數(shù)不能換行

var func = ()
??????=> 1; // SyntaxError: expected expression, got '=>'

如果開發(fā)中確實(shí)一行搞不定,邏輯很多,就加{},你就想怎么換行怎么換行了。

var func = ()=>{
??return '來(lái)?。』ハ鄠Π?!'; // 1.加{} 2.加return
}

4、箭頭函數(shù)使用場(chǎng)景

JavaScript中this的故事已經(jīng)是非常古老了,每一個(gè)函數(shù)都有自己的上下文。

以下例子的目的是使用jQuery來(lái)展示一個(gè)每秒都會(huì)更新的時(shí)鐘:

$('.time').each(function () {
?setInterval(function () {
??$(this).text(Date.now());
?}, 1000);
});

當(dāng)嘗試在setInterval的回調(diào)中使用this來(lái)引用DOM元素時(shí),很不幸,我們得到的只是一個(gè)屬于回調(diào)函數(shù)自身

上下文的this。一個(gè)通常的解決辦法是定義一個(gè)that或者self變量:

$('.time').each(function () {
?var self = this;
?setInterval(function () {
??$(self).text(Date.now());
?}, 1000);
});

但當(dāng)使用箭頭函數(shù)時(shí),這個(gè)問(wèn)題就不復(fù)存在了。因?yàn)樗划a(chǎn)生屬于它自己上下文的this:

$('.time').each(function () {
?setInterval(() => $(this).text(Date.now()), 1000);
});

箭頭函數(shù)的另一個(gè)用處是簡(jiǎn)化回調(diào)函數(shù)。

// 正常函數(shù)寫法
[1,2,3].map(function (x) {
?return x * x;
});
?
// 箭頭函數(shù)寫法
[1,2,3].map(x => x * x);

當(dāng)然也可以在事件監(jiān)聽(tīng)函數(shù)里使用:

document.body.addEventListener('click', event=>console.log(event, this)); 
// EventObject, BodyElement

5、總結(jié)

5.1 箭頭函數(shù)優(yōu)點(diǎn)

箭頭函數(shù)是使用=>語(yǔ)法的函數(shù)簡(jiǎn)寫形式。這在語(yǔ)法上與 C#、Java 8 、Python( lambda 函數(shù))和 CoffeeScript 的

相關(guān)特性非常相似。

非常簡(jiǎn)潔的語(yǔ)法,使用箭頭函數(shù)比普通函數(shù)少些動(dòng)詞,如:function或return。

() => { ... } // 零個(gè)參數(shù)用 () 表示。
x => { ... } // 一個(gè)參數(shù)可以省略 ()。
(x, y) => { ... } // 多參數(shù)不能省略 ()。

如果只有一個(gè)return,{}可以省略。
更直觀的作用域和 this的綁定,它能讓我們能很好的處理this的指向問(wèn)題。箭頭函數(shù)加上let關(guān)鍵字的使用,將會(huì)讓我們javascript代碼上一個(gè)層次。

5.2 箭頭函數(shù)使用場(chǎng)景

箭頭函數(shù)適合于無(wú)復(fù)雜邏輯或者無(wú)副作用的純函數(shù)場(chǎng)景下,例如用在map、reduce、filter的回調(diào)函數(shù)定義
中,另外目前vue、react、node等庫(kù),都大量使用箭頭函數(shù),直接定義function的情況已經(jīng)很少了。
各位同學(xué)在寫新項(xiàng)目的時(shí)候,要不斷的琢磨箭頭函數(shù)使用場(chǎng)景、特點(diǎn),享受使用箭頭函數(shù)帶來(lái)的便利,這樣才能更快地成長(zhǎng)。

下面是廖雪峰網(wǎng)站的補(bǔ)充

ES6標(biāo)準(zhǔn)新增了一種新的函數(shù):Arrow Function(箭頭函數(shù))。

為什么叫Arrow Function?因?yàn)樗亩x用的就是一個(gè)箭頭:

x => x * x

上面的箭頭函數(shù)相當(dāng)于:

function (x) {
return x * x;
}

箭頭函數(shù)相當(dāng)于匿名函數(shù),并且簡(jiǎn)化了函數(shù)定義。箭頭函數(shù)有兩種格式,一種像上面的,只包含一個(gè)表達(dá)式,連{ ... }和return都省略掉了。還有一種可以包含多條語(yǔ)句,這時(shí)候就不能省略{ ... }和return:

>
x => {
?if (x > 0) {
??return x * x;
?}
?else {
??return - x * x;
?}
}

如果參數(shù)不是一個(gè),就需要用括號(hào)()括起來(lái):

// 兩個(gè)參數(shù):
(x, y) => x * x + y * y
?
// 無(wú)參數(shù):
() => 3.14
?
// 可變參數(shù):
(x, y, ...rest) => {
?var i, sum = x + y;
?for (i=0; i<rest.length; i++) {
??sum += rest[i];
?}
?return sum;
}

如果要返回一個(gè)對(duì)象,就要注意,如果是單表達(dá)式,這么寫的話會(huì)報(bào)錯(cuò):

// SyntaxError:
x => { foo: x }

因?yàn)楹秃瘮?shù)體的{ ... }有語(yǔ)法沖突,所以要改為:

// ok:
x => ({ foo: x })

this

箭頭函數(shù)看上去是匿名函數(shù)的一種簡(jiǎn)寫,但實(shí)際上,箭頭函數(shù)和匿名函數(shù)有個(gè)明顯的區(qū)別:箭頭函數(shù)內(nèi)部的this是詞法作用域,由上下文確定。

回顧前面的例子,由于JavaScript函數(shù)對(duì)this綁定的錯(cuò)誤處理,下面的例子無(wú)法得到預(yù)期結(jié)果:

var obj = {
?birth: 1990,
?getAge: function () {
??var b = this.birth; // 1990
??var fn = function () {
???return new Date().getFullYear() - this.birth; // this指向window或undefined
??};
??return fn();
?}
};

現(xiàn)在,箭頭函數(shù)完全修復(fù)了this的指向,this總是指向詞法作用域,也就是外層調(diào)用者obj:

var obj = {
?birth: 1990,
?getAge: function () {
??var b = this.birth; // 1990
??var fn = () => new Date().getFullYear() - this.birth; // this指向obj對(duì)象
??return fn();
?}
};
obj.getAge(); // 25

如果使用箭頭函數(shù),以前的那種hack寫法:

var that = this;

就不再需要了。

由于this在箭頭函數(shù)中已經(jīng)按照詞法作用域綁定了,所以,用call()或者apply()調(diào)用箭頭函數(shù)時(shí),無(wú)法對(duì)this進(jìn)行綁定,即傳入的第一個(gè)參數(shù)被忽略:

var obj = {
?birth: 1990,
?getAge: function (year) {
??var b = this.birth; // 1990
??var fn = (y) => y - this.birth; // this.birth仍是1990
??return fn.call({birth:2000}, year);
?}
};
obj.getAge(2015); // 25

練習(xí)

請(qǐng)使用箭頭函數(shù)簡(jiǎn)化排序時(shí)傳入的函數(shù):

<script>
'use strict'
var arr = [10, 20, 1, 2];
arr.sort((x, y) => {
?if (x < y) return -1
?else if (x > y) return 1
?else return 0
});
console.log(arr); // [1, 2, 10, 20]
</script>


 

以上就是ES6標(biāo)準(zhǔn) Arrow Function(箭頭函數(shù)=>)的詳細(xì)內(nèi)容