摘要:回顧我們先來回顧下箭頭函數(shù)的基本語法。主要區(qū)別包括沒有箭頭函數(shù)沒有,所以需要通過查找作用域鏈來確定的值。箭頭函數(shù)并沒有方法,不能被用作構(gòu)造函數(shù),如果通過的方式調(dià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}
很多時候,你可能想不到要這樣用,所以再來舉個例子,比如在 React 與 Immutable 的技術(shù)選型中,我們處理一個事件會這樣做:
handleEvent = () => {
this.setState({
data: this.state.data.set("key", "value")
})
};
其實就可以簡化為:
handleEvent = () => {
this.setState(({data}) => ({
data: data.set("key", "value")
}))
};
比較
本篇我們重點比較一下箭頭函數(shù)與普通函數(shù)。
主要區(qū)別包括:
1.沒有 this箭頭函數(shù)沒有 this,所以需要通過查找作用域鏈來確定 this 的值。
這就意味著如果箭頭函數(shù)被非箭頭函數(shù)包含,this 綁定的就是最近一層非箭頭函數(shù)的 this。
模擬一個實際開發(fā)中的例子:
我們的需求是點擊一個按鈕,改變該按鈕的背景色。
為了方便開發(fā),我們抽離一個 Button 組件,當(dāng)需要使用的時候,直接:
// 傳入元素 id 值即可綁定該元素點擊時改變背景色的事件
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é)果卻是報錯 Uncaught TypeError: Cannot read property "style" of undefined
這是因為當(dāng)使用 addEventListener() 為一個元素注冊事件的時候,事件函數(shù)里的 this 值是該元素的引用。
所以如果我們在 setBgColor 中 console.log(this),this 指向的是按鈕元素,那 this.element 就是 undefined,報錯自然就理所當(dāng)然了。
也許你會問,既然 this 都指向了按鈕元素,那我們直接修改 setBgColor 函數(shù)為:
Button.prototype.setBgColor = function() {
this.style.backgroundColor = "#1abc9c"
};
不就可以解決這個問題了?
確實可以這樣做,但是在實際的開發(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 強制綁定 setBgColor() 的 this 為實例對象
使用 ES6,我們可以更好的解決這個問題:
Button.prototype.bindEvent = function() {
this.element.addEventListener("click", event => this.setBgColor(event), false);
};
由于箭頭函數(shù)沒有 this,所以會向外層查找 this 的值,即 bindEvent 中的 this,此時 this 指向?qū)嵗龑ο螅钥梢哉_的調(diào)用 this.setBgColor 方法, 而 this.setBgColor 中的 this 也會正確指向?qū)嵗龑ο蟆?/p>
在這里再額外提一點,就是注意 bindEvent 和 setBgColor 在這里使用的是普通函數(shù)的形式,而非箭頭函數(shù),如果我們改成箭頭函數(shù),會導(dǎo)致函數(shù)里的 this 指向 window 對象 (非嚴格模式下)。
最后,因為箭頭函數(shù)沒有 this,所以也不能用 call()、apply()、bind() 這些方法改變 this 的指向,可以看一個例子:
var value = 1;
var result = (() => this.value).bind({value: 2})();
console.log(result); // 1
2. 沒有 arguments
箭頭函數(shù)沒有自己的 arguments 對象,這不一定是件壞事,因為箭頭函數(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ù)時,執(zhí)行 [[Construct]] 方法,創(chuàng)建一個實例對象,然后再執(zhí)行函數(shù)體,將 this 綁定到實例上。
當(dāng)直接調(diào)用的時候,執(zhí)行 [[Call]] 方法,直接執(zhí)行函數(shù)體。
箭頭函數(shù)并沒有 [[Construct]] 方法,不能被用作構(gòu)造函數(shù),如果通過 new 的方式調(diào)用,會報錯。
var Foo = () => {};
var foo = new Foo(); // TypeError: Foo is not a constructor
4. 沒有 new.target
因為不能使用 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); // undefined
6. 沒有 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ù)表達式的語法比函數(shù)表達式更短,并且不綁定自己的this,arguments,super或 new.target。這些函數(shù)表達式最適合用于非方法函數(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)
})()
但是注意:使用以下這種寫法卻會報錯:
(() => {
console.log(1)
}())
為什么會報錯呢?嘿嘿,如果你知道,可以告訴我~
ES6 系列ES6 系列目錄地址:https://github.com/mqyqingfeng/Blog
ES6 系列預(yù)計寫二十篇左右,旨在加深 ES6 部分知識點的理解,重點講解塊級作用域、標簽?zāi)0濉⒓^函數(shù)、Symbol、Set、Map 以及 Promise 的模擬實現(xiàn)、模塊加載方案、異步處理等內(nèi)容。
如果有錯誤或者不嚴謹?shù)牡胤剑垊?wù)必給予指正,十分感謝。如果喜歡或者有所啟發(fā),歡迎 star,對作者也是一種鼓勵。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.hztianpu.com/yun/107949.html
摘要:如果所有函數(shù)都是尾調(diào)用,那么完全可以做到每次執(zhí)行時,調(diào)用幀只有一項,這將大大節(jié)省內(nèi)存。等同于等同于注意,只有不再用到外層函數(shù)的內(nèi)部變量,內(nèi)層函數(shù)的調(diào)用幀才會取代外層函數(shù)的調(diào)用幀,否則就無法進行尾調(diào)用優(yōu)化。 showImg(https://segmentfault.com/img/bVbrTHp?w=1080&h=1920); 1. 函數(shù)參數(shù)的默認值 1.1 用法 在ES6之前是不能為...
摘要:如果所有函數(shù)都是尾調(diào)用,那么完全可以做到每次執(zhí)行時,調(diào)用幀只有一項,這將大大節(jié)省內(nèi)存。等同于等同于注意,只有不再用到外層函數(shù)的內(nèi)部變量,內(nèi)層函數(shù)的調(diào)用幀才會取代外層函數(shù)的調(diào)用幀,否則就無法進行尾調(diào)用優(yōu)化。 showImg(https://segmentfault.com/img/bVbrTHp?w=1080&h=1920); 1. 函數(shù)參數(shù)的默認值 1.1 用法 在ES6之前是不能為...
摘要:沒有箭頭函數(shù)沒有自己的對象,這不一定是件壞事,因為箭頭函數(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)缺點深入系列第十五篇,講解各種繼承方式和優(yōu)缺點。對于解釋型語言例如來說,通過詞法分析語法分析語法樹,就可以開始解釋執(zhí)行了。 JavaScript深入之繼承的多種方式和優(yōu)缺點 JavaScript深入系列第十五篇,講解JavaScript各種繼承方式和優(yōu)缺點。 寫在前面 本文講解JavaScript各種繼承方式和優(yōu)缺點。 但是注意: 這篇文章更像是筆記,哎,再讓我...
摘要:簡單的說就是,新語法編譯器舊語法。說明所以,對于新特性,我們可以通過使用,也可以通過語法轉(zhuǎn)化來達到兼容。 0x001 polyfill 我們都知道,js總是一直存在著兼容性問題,雖然其他語言也存在著兼容性問題,比如c++、java,但那種兼容性是新特性在舊版本上的不兼容,js則存在著各種奇形怪哉的不兼容。這其中有著非常復(fù)雜的歷史和時代的原因,并不加以累述。而解決兼容性問題的方法在以前只...
閱讀 4207·2021-07-28 18:10
閱讀 2801·2019-08-30 15:44
閱讀 1360·2019-08-30 14:07
閱讀 3732·2019-08-29 17:20
閱讀 1766·2019-08-26 18:35
閱讀 3769·2019-08-26 13:42
閱讀 1989·2019-08-26 11:58
閱讀 1796·2019-08-23 18:33