0.爲何會出現箭頭函數?javascript
1.傳統的javascript函數語法並無提供任何的靈活性,每一次你須要定義一個函數時,你都必須輸入function () {},這至少會出現兩個問題,ES6箭頭函數都圓滿解決了它,vue
第一個問題:代碼輸入快了容易輸錯成 funciton或者functoin或者其它,可是=>這個玩意你要是再寫錯就只能說有點過度了。java
第二個問題:節省大量代碼,咱們先不用管下面的ES6代碼爲何這樣的語法能實現一樣的功能,咱們就直觀的感覺一下代碼量。node
ES5寫法:react
function addFive(num){ return num+5; } alert(addFive(10));
ES6寫法:面試
var addFive = num=>num+5; alert(addFive(5));
沒有function、沒有return,沒有(),沒有{},這些全變成了浮雲,世界好清靜。express
從上面咱們就能夠看到,使用箭頭函數不只僅可以避免錯誤,同時還能讓咱們少一丟丟代碼,固然實際工做中遠比這個代碼量節省更多。
一方面是由於積累效應,每一部分少一丟丟合起來就多了,一方面是它還有更能節省代碼和大幅提升工做效率的場景。app
接下來咱們就說說今天的主角--箭頭函數。函數
ES6標準新增了一種新的函數:Arrow Function(箭頭函數),也稱「胖箭頭函數」, 容許this
使用「箭頭」(=>)定義函數,是一種簡寫的函數表達式。
一、箭頭函數語法
在ES5中咱們實現一個求和的函數:
var sum = function(x, y) { return x + y }
要使用箭頭函數,能夠分兩步實現一樣的函數功能:
首先使用=>來替代關鍵詞function
var sum = (x, y) => { return x + y }
這個特性很是好!!!
前面咱們已經說過用=>來替代關鍵詞function就意味着不會寫錯function了,這真是一個絕妙的設計思想!
其次,函數體只有一條返回語句時, 咱們能夠省略括號{}和return關鍵詞:
var sum = (x, y) => x + y
再誇張一點點,若是隻有一個參數時,()可省略。
這是箭頭函數最簡潔的形式,經常使用於做用簡單的處理函數,好比過濾:
// 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"]
箭頭函數的主要使用模式以下:
// 一個參數對應一個表達式 param => expression;// 例如 x => x+2; // 多個參數對應一個表達式 (param [, param]) => expression; //例如 (x,y) => (x + y); // 一個參數對應多個表示式 param => {statements;} //例如 x = > { x++; return x;}; // 多個參數對應多個表達式 ([param] [, param]) => {statements} // 例如 (x,y) => { x++;y++;return x*y;}; //表達式裏沒有參數 () => expression; //例如var flag = (() => 2)(); flag等於2 () => {statements;} //例如 var flag = (() => {return 1;})(); flag就等於1 //傳入一個表達式,返回一個對象 ([param]) => ({ key: value }); //例如 var fuc = (x) => ({key:x}) var object = fuc(1); alert(object);//{key:1}
你們不要以爲好多啊,好麻煩,其實這些根本不復雜。投入一次,受益終生。(怎麼感受我像賣保險的……),寫一兩次你就習慣新的寫法了。
二、箭頭函數中的 this
箭頭函數內的this值繼承自外圍做用域。運行時它會首先到它的父做用域找,若是父做用域仍是箭頭函數,那麼接着向上找,直到找到咱們要的this指向。
咱們先看一道經典的關於this的面試題:
var name = 'leo'; var teacher = { name: "大彬哥", showName: function () { function showTest() { alert(this.name); } showTest(); } }; teacher.showName();//結果是 leo,而咱們期待的是大彬哥,這裏this指向了window,咱們期待指向teacher
你們知道,ES5中的this說好聽了叫"靈活",說很差聽就是瞎搞,特別容易出問題.並且面試還很是愛考,工做更不用說了,常常給咱們開發搗亂,出現很差調試的bug,用E箭頭函數解決這個問題就很駕輕就熟了。
var name = 'leo'; var teacher = { name: "大彬哥", showName: function () { let showTest = ()=>alert(this.name); showTest(); } }; teacher.showName();
箭頭函數中的this實際上是父級做用域中的this。箭頭函數引用了父級的變量詞法做用域就是一個變量的做用在定義的時候就已經被定義好,當在本做用域中找不到變量,就會一直向父做用域中查找,直到找到爲止。
因爲this在箭頭函數中已經按照詞法做用域綁定了,因此,用call或者apply調用箭頭函數時,沒法對this進行綁定,即傳入的第一個參數被忽略:
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已經在詞法層面完成了綁定,經過call或apply方法調用一個函數時,只是傳入了參數而已,對this並無什麼影響 。所以,這個設計節省了開發者思考上下文綁定的時間。
三、箭頭函數的特性
3.1 箭頭函數沒有 arguments
箭頭函數不只沒有this,經常使用的arguments也沒有。若是你能獲取到arguments,那它
必定是來自父做用域的。
function foo() { return () => console.log(arguments) } foo(1, 2)(3, 4) // 1,2
上例中若是箭頭函數有arguments,就應該輸出的是3,4而不是1,2。
箭頭函數不綁定arguments,取而代之用rest參數…解決
var foo = (...args) => { return args } console.log(foo(1,3,56,36,634,6)) // [1, 3, 56, 36, 634, 6]
箭頭函數要實現相似純函數的效果,必須剔除外部狀態。咱們能夠看出,箭頭函數除了傳入的參數以外,真的在普通函數裏常見的this、arguments、caller是通通沒有的!
若是你在箭頭函數引用了this、arguments或者參數以外的變量,那它們必定不是箭頭函數自己包含的,而是從父級做用域繼承的。
3.2 箭頭函數中不能使用 new
let Person = (name) => { this.name = name; }; let one = new Person("galler");
運行該程序,則出現TypeError: Person is not a constructor
3.3 箭頭函數能夠與變量解構結合使用。
const full = ({ first, last }) => first + ' ' + last; // 等同於 function full(person) { return person.first + ' ' + person.last; } full({first: 1, last: 5}) // '1 5'
3.4 箭頭函數沒有原型屬性
var foo = () => {}; console.log(foo.prototype) //undefined
由此能夠看出箭頭函數沒有原型。
另外一個錯誤是在原型上使用箭頭函數,如:
function A() { this.foo = 1 } A.prototype.bar = () => console.log(this.foo) let a = new A() a.bar() //undefined
一樣,箭頭函數中的this不是指向A,而是根據變量查找規則回溯到了全局做用域。一樣,使用普通函數就不存在問題。箭頭函數中不可加new,也就是說箭頭函數不能當構造函數進行使用。
3.5 箭頭函數不能換行
var func = () => 1; // SyntaxError: expected expression, got '=>'
若是開發中確實一行搞不定,邏輯不少,就加{},你就想怎麼換行怎麼換行了。
var func = ()=>{ return '來啊!互相傷害啊!'; // 1.加{} 2.加return }
四、箭頭函數使用場景
JavaScript中this的故事已是很是古老了,每個函數都有本身的上下文。
如下例子的目的是使用jQuery來展現一個每秒都會更新的時鐘:
$('.time').each(function () { setInterval(function () { $(this).text(Date.now()); }, 1000); });
當嘗試在setInterval的回調中使用this來引用DOM元素時,很不幸,咱們獲得的只是一個屬於回調函數自身
上下文的this。一個一般的解決辦法是定義一個that或者self變量:
$('.time').each(function () { var self = this; setInterval(function () { $(self).text(Date.now()); }, 1000); });
但當使用箭頭函數時,這個問題就不復存在了。由於它不產生屬於它本身上下文的this:
$('.time').each(function () { setInterval(() => $(this).text(Date.now()), 1000); });
箭頭函數的另外一個用處是簡化回調函數。
// 正常函數寫法 [1,2,3].map(function (x) { return x * x; }); // 箭頭函數寫法 [1,2,3].map(x => x * x);
固然也能夠在事件監聽函數裏使用:
document.body.addEventListener('click', event=>console.log(event, this)); // EventObject, BodyElement
五、總結
5.1 箭頭函數優勢
箭頭函數是使用=>語法的函數簡寫形式。這在語法上與 C#、Java 8 、Python( lambda 函數)和 CoffeeScript 的
相關特性很是類似。
很是簡潔的語法,使用箭頭函數比普通函數少些動詞,如:function或return。
() => { ... } // 零個參數用 () 表示。 x => { ... } // 一個參數能夠省略 ()。 (x, y) => { ... } // 多參數不能省略 ()。 若是隻有一個return,{}能夠省略。
更直觀的做用域和 this的綁定,它能讓咱們能很好的處理this的指向問題。箭頭函數加上let關鍵字的使用,將會讓咱們javascript代碼上一個層次。
5.2 箭頭函數使用場景
箭頭函數適合於無複雜邏輯或者無反作用的純函數場景下,例如用在map、reduce、filter的回調函數定義
中,另外目前vue、react、node等庫,都大量使用箭頭函數,直接定義function的狀況已經不多了。
各位同窗在寫新項目的時候,要不斷的琢磨箭頭函數使用場景、特色,享受使用箭頭函數帶來的便利,這樣才能更快地成長。