摘要:回顧我們先來回顧下箭頭函數(shù)的基本語法。主要區(qū)別包括沒有箭頭函數(shù)沒有,所以需要通過查找作用域鏈來確定的值。箭頭函數(shù)并沒有方法,不能被用作構(gòu)造函數(shù),如果通過的方式調(diào)用,會報(bào)錯。
回顧
我們先來回顧下箭頭函數(shù)的基本語法。
ES6 增加了箭頭函數(shù):
let func = value => value;
相當(dāng)于:
let func = function (value) { return value; };
如果需要給函數(shù)傳入多個參數(shù):
let func = (value, num) => value * num;
如果函數(shù)的代碼塊需要多條語句:
let func = (value, num) => { return value * num };
如果需要直接返回一個對象:
let func = (value, num) => ({total: value * num});
與變量解構(gòu)結(jié)合:
let func = ({value, num}) => ({total: value * num}) // 使用 var result = func({ value: 10, num: 10 }) console.log(result); // {total: 100}
很多時(shí)候,你可能想不到要這樣用,所以再來舉個例子,比如在 React 與 Immutable 的技術(shù)選型中,我們處理一個事件會這樣做:
handleEvent = () => { this.setState({ data: this.state.data.set("key", "value") }) };
其實(shí)就可以簡化為:
handleEvent = () => { this.setState(({data}) => ({ data: data.set("key", "value") })) };比較
本篇我們重點(diǎn)比較一下箭頭函數(shù)與普通函數(shù)。
主要區(qū)別包括:
1.沒有 this箭頭函數(shù)沒有 this,所以需要通過查找作用域鏈來確定 this 的值。
這就意味著如果箭頭函數(shù)被非箭頭函數(shù)包含,this 綁定的就是最近一層非箭頭函數(shù)的 this。
模擬一個實(shí)際開發(fā)中的例子:
我們的需求是點(diǎn)擊一個按鈕,改變該按鈕的背景色。
為了方便開發(fā),我們抽離一個 Button 組件,當(dāng)需要使用的時(shí)候,直接:
// 傳入元素 id 值即可綁定該元素點(diǎn)擊時(shí)改變背景色的事件 new Button("button")
HTML 代碼如下:
JavaScript 代碼如下:
function Button(id) { this.element = document.querySelector("#" + id); this.bindEvent(); } Button.prototype.bindEvent = function() { this.element.addEventListener("click", this.setBgColor, false); }; Button.prototype.setBgColor = function() { this.element.style.backgroundColor = "#1abc9c" }; var button = new Button("button");
看著好像沒有問題,結(jié)果卻是報(bào)錯 Uncaught TypeError: Cannot read property "style" of undefined
這是因?yàn)楫?dāng)使用 addEventListener() 為一個元素注冊事件的時(shí)候,事件函數(shù)里的 this 值是該元素的引用。
所以如果我們在 setBgColor 中 console.log(this),this 指向的是按鈕元素,那 this.element 就是 undefined,報(bào)錯自然就理所當(dāng)然了。
也許你會問,既然 this 都指向了按鈕元素,那我們直接修改 setBgColor 函數(shù)為:
Button.prototype.setBgColor = function() { this.style.backgroundColor = "#1abc9c" };
不就可以解決這個問題了?
確實(shí)可以這樣做,但是在實(shí)際的開發(fā)中,我們可能會在 setBgColor 中還調(diào)用其他的函數(shù),比如寫成這種:
Button.prototype.setBgColor = function() { this.setElementColor(); this.setOtherElementColor(); };
所以我們還是希望 setBgColor 中的 this 是指向?qū)嵗龑ο蟮模@樣就可以調(diào)用其他的函數(shù)。
利用 ES5,我們一般會這樣做:
Button.prototype.bindEvent = function() { this.element.addEventListener("click", this.setBgColor.bind(this), false); };
為避免 addEventListener 的影響,使用 bind 強(qiáng)制綁定 setBgColor() 的 this 為實(shí)例對象
使用 ES6,我們可以更好的解決這個問題:
Button.prototype.bindEvent = function() { this.element.addEventListener("click", event => this.setBgColor(event), false); };
由于箭頭函數(shù)沒有 this,所以會向外層查找 this 的值,即 bindEvent 中的 this,此時(shí) this 指向?qū)嵗龑ο螅钥梢哉_的調(diào)用 this.setBgColor 方法, 而 this.setBgColor 中的 this 也會正確指向?qū)嵗龑ο蟆?/p>
在這里再額外提一點(diǎn),就是注意 bindEvent 和 setBgColor 在這里使用的是普通函數(shù)的形式,而非箭頭函數(shù),如果我們改成箭頭函數(shù),會導(dǎo)致函數(shù)里的 this 指向 window 對象 (非嚴(yán)格模式下)。
最后,因?yàn)榧^函數(shù)沒有 this,所以也不能用 call()、apply()、bind() 這些方法改變 this 的指向,可以看一個例子:
var value = 1; var result = (() => this.value).bind({value: 2})(); console.log(result); // 12. 沒有 arguments
箭頭函數(shù)沒有自己的 arguments 對象,這不一定是件壞事,因?yàn)榧^函數(shù)可以訪問外圍函數(shù)的 arguments 對象:
function constant() { return () => arguments[0] } var result = constant(1); console.log(result()); // 1
那如果我們就是要訪問箭頭函數(shù)的參數(shù)呢?
你可以通過命名參數(shù)或者 rest 參數(shù)的形式訪問參數(shù):
let nums = (...nums) => nums;3. 不能通過 new 關(guān)鍵字調(diào)用
JavaScript 函數(shù)有兩個內(nèi)部方法:[[Call]] 和 [[Construct]]。
當(dāng)通過 new 調(diào)用函數(shù)時(shí),執(zhí)行 [[Construct]] 方法,創(chuàng)建一個實(shí)例對象,然后再執(zhí)行函數(shù)體,將 this 綁定到實(shí)例上。
當(dāng)直接調(diào)用的時(shí)候,執(zhí)行 [[Call]] 方法,直接執(zhí)行函數(shù)體。
箭頭函數(shù)并沒有 [[Construct]] 方法,不能被用作構(gòu)造函數(shù),如果通過 new 的方式調(diào)用,會報(bào)錯。
var Foo = () => {}; var foo = new Foo(); // TypeError: Foo is not a constructor4. 沒有 new.target
因?yàn)椴荒苁褂?new 調(diào)用,所以也沒有 new.target 值。
關(guān)于 new.target,可以參考 http://es6.ruanyifeng.com/#docs/class#new-target-%E5%B1%9E%E6%80%A7
5. 沒有原型由于不能使用 new 調(diào)用箭頭函數(shù),所以也沒有構(gòu)建原型的需求,于是箭頭函數(shù)也不存在 prototype 這個屬性。
var Foo = () => {}; console.log(Foo.prototype); // undefined6. 沒有 super
連原型都沒有,自然也不能通過 super 來訪問原型的屬性,所以箭頭函數(shù)也是沒有 super 的,不過跟 this、arguments、new.target 一樣,這些值由外圍最近一層非箭頭函數(shù)決定。
總結(jié)最后,關(guān)于箭頭函數(shù),引用 MDN 的介紹就是:
An arrow function expression has a shorter syntax than a function expression and does not have its own this, arguments, super, or new.target. These function expressions are best suited for non-method functions, and they cannot be used as constructors.
翻譯過來就是:
箭頭函數(shù)表達(dá)式的語法比函數(shù)表達(dá)式更短,并且不綁定自己的this,arguments,super或 new.target。這些函數(shù)表達(dá)式最適合用于非方法函數(shù)(non-method functions),并且它們不能用作構(gòu)造函數(shù)。
那么什么是 non-method functions 呢?
我們先來看看 method 的定義:
A method is a function which is a property of an object.
對象屬性中的函數(shù)就被稱之為 method,那么 non-mehtod 就是指不被用作對象屬性中的函數(shù)了,可是為什么說箭頭函數(shù)更適合 non-method 呢?
讓我們來看一個例子就明白了:
var obj = { i: 10, b: () => console.log(this.i, this), c: function() { console.log( this.i, this) } } obj.b(); // undefined Window obj.c(); // 10, Object {...}自執(zhí)行函數(shù)
自執(zhí)行函數(shù)的形式為:
(function(){ console.log(1) })()
或者
(function(){ console.log(1) }())
利用箭頭簡化自執(zhí)行函數(shù)的寫法:
(() => { console.log(1) })()
但是注意:使用以下這種寫法卻會報(bào)錯:
(() => { console.log(1) }())
為什么會報(bào)錯呢?嘿嘿,如果你知道,可以告訴我~
ES6 系列ES6 系列目錄地址:https://github.com/mqyqingfeng/Blog
ES6 系列預(yù)計(jì)寫二十篇左右,旨在加深 ES6 部分知識點(diǎn)的理解,重點(diǎn)講解塊級作用域、標(biāo)簽?zāi)0濉⒓^函數(shù)、Symbol、Set、Map 以及 Promise 的模擬實(shí)現(xiàn)、模塊加載方案、異步處理等內(nèi)容。
如果有錯誤或者不嚴(yán)謹(jǐn)?shù)牡胤剑垊?wù)必給予指正,十分感謝。如果喜歡或者有所啟發(fā),歡迎 star,對作者也是一種鼓勵。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/107949.html
摘要:如果所有函數(shù)都是尾調(diào)用,那么完全可以做到每次執(zhí)行時(shí),調(diào)用幀只有一項(xiàng),這將大大節(jié)省內(nèi)存。等同于等同于注意,只有不再用到外層函數(shù)的內(nèi)部變量,內(nèi)層函數(shù)的調(diào)用幀才會取代外層函數(shù)的調(diào)用幀,否則就無法進(jìn)行尾調(diào)用優(yōu)化。 showImg(https://segmentfault.com/img/bVbrTHp?w=1080&h=1920); 1. 函數(shù)參數(shù)的默認(rèn)值 1.1 用法 在ES6之前是不能為...
摘要:如果所有函數(shù)都是尾調(diào)用,那么完全可以做到每次執(zhí)行時(shí),調(diào)用幀只有一項(xiàng),這將大大節(jié)省內(nèi)存。等同于等同于注意,只有不再用到外層函數(shù)的內(nèi)部變量,內(nèi)層函數(shù)的調(diào)用幀才會取代外層函數(shù)的調(diào)用幀,否則就無法進(jìn)行尾調(diào)用優(yōu)化。 showImg(https://segmentfault.com/img/bVbrTHp?w=1080&h=1920); 1. 函數(shù)參數(shù)的默認(rèn)值 1.1 用法 在ES6之前是不能為...
摘要:沒有箭頭函數(shù)沒有自己的對象,這不一定是件壞事,因?yàn)榧^函數(shù)可以訪問外圍函數(shù)的對象那如果我們就是要訪問箭頭函數(shù)的參數(shù)呢你可以通過命名參數(shù)或者參數(shù)的形式訪問參數(shù)不能通過關(guān)鍵字調(diào)用函數(shù)有兩個內(nèi)部方法和。 1、基本語法回顧 我們先來回顧下箭頭函數(shù)的基本語法。ES6 增加了箭頭函數(shù): var f = v => v; // 等同于 var f = function (v) { return ...
摘要:深入之繼承的多種方式和優(yōu)缺點(diǎn)深入系列第十五篇,講解各種繼承方式和優(yōu)缺點(diǎn)。對于解釋型語言例如來說,通過詞法分析語法分析語法樹,就可以開始解釋執(zhí)行了。 JavaScript深入之繼承的多種方式和優(yōu)缺點(diǎn) JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 寫在前面 本文講解JavaScript各種繼承方式和優(yōu)缺點(diǎn)。 但是注意: 這篇文章更像是筆記,哎,再讓我...
摘要:簡單的說就是,新語法編譯器舊語法。說明所以,對于新特性,我們可以通過使用,也可以通過語法轉(zhuǎn)化來達(dá)到兼容。 0x001 polyfill 我們都知道,js總是一直存在著兼容性問題,雖然其他語言也存在著兼容性問題,比如c++、java,但那種兼容性是新特性在舊版本上的不兼容,js則存在著各種奇形怪哉的不兼容。這其中有著非常復(fù)雜的歷史和時(shí)代的原因,并不加以累述。而解決兼容性問題的方法在以前只...
閱讀 3876·2021-07-28 18:10
閱讀 2583·2019-08-30 15:44
閱讀 1093·2019-08-30 14:07
閱讀 3465·2019-08-29 17:20
閱讀 1583·2019-08-26 18:35
閱讀 3541·2019-08-26 13:42
閱讀 1821·2019-08-26 11:58
閱讀 1594·2019-08-23 18:33