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