您好,登錄后才能下訂單哦!
小編這次要給大家分享的是詳解JS箭頭函數和常規函數,文章內容豐富,感興趣的小伙伴可以來了解一下,希望大家閱讀完這篇文章之后能夠有所收獲。
本文實例講述了JS箭頭函數和常規函數之間的區別。分享給大家供大家參考,具體如下:
在 JavaScript 中,你可以通過多種方式去定義函數。
第一種常用的方法是使用關鍵字 function
:
// 函數聲明 function greet(who) { return `Hello, ${who}!`; } // 函數表達式 const greet = function(who) { return `Hello, ${who}`; }
代碼中的函數聲明和函數表達式被稱為“常規函數”。
從 ES2015 開始,第二種可用的方法是 箭頭函數 語法:
const greet = (who) => { return `Hello, ${who}!`; }
雖然兩者的語法都能夠定義函數,但是在開發時該怎么選擇呢?這是個好問題。
在本文中,我將展示兩者之間的主要區別,以供你能夠根據需要選擇正確的語法。
在常規 JavaScript 函數內部,this
值(即執行上下文)是動態的。
動態上下文意味著 this
的值取決于如何調用函數。在 JavaScript 中,有 4 種調用常規函數的方式。
在簡單調用過程中,this
的值等于全局對象(如果函數在嚴格模式下運行,則為 undefined
):
function myFunction() { console.log(this); } // 簡單調用 myFunction(); // logs global object (window)
在方法調用過程中,this
的值是擁有該方法的對象:
const myObject = { method() { console.log(this); } }; // 方法調用 myObject.method(); // logs "myObject"
在使用 myFunc.call(context, arg1, ..., argN)
或 myFunc.apply(context, [arg1, ..., argN])
的間接調用中,this
的值等于第一個參數:
function myFunction() { console.log(this); } const myContext = { value: 'A' }; myFunction.call(myContext); // logs { value: 'A' } myFunction.apply(myContext); // logs { value: 'A' }
在使用關鍵字 new
的構造函數調用期間,this
等于新創建的實例:
function MyFunction() { console.log(this); } new MyFunction(); // logs an instance of MyFunction
箭頭函數中 this
的行為與常規函數的 this
行為有很大不同。
無論如何執行或在何處執行,箭頭函數內部的 this
值始終等于外部函數的 this
值。換句話說,箭頭函數可按詞法解析 this
,箭頭函數沒有定義自己的執行上下文。
在以下示例中,myMethod()
是箭頭函數 callback()
的外部函數:
const myObject = { myMethod(items) { console.log(this); // logs "myObject" const callback = () => { console.log(this); // logs "myObject" }; items.forEach(callback); } }; myObject.myMethod([1, 2, 3]);
箭頭函數 callback()
中的 this
值等于外部函數 myMethod()
的 this
。
this
詞法解析是箭頭函數的重要功能之一。在方法內部使用回調時,要確保箭頭函數沒有定義自己的 this
:不再有 const self = this
或者 callback.bind(this)
這種解決方法。
如上一節所述,常規函數可以輕松的構造對象。
例如用 Car()
函數創建汽車的實例:
function Car(color) { this.color = color; } const redCar = new Car('red'); redCar instanceof Car; // => true
Car
是常規函數,使用關鍵字 new
調用時會創建 Car
類型的新實例。
this
詞法解決了箭頭函數不能用作構造函數。
如果你嘗試調用帶有 new
關鍵字前綴的箭頭函數,則 JavaScript 會引發錯誤:
const Car = (color) => { this.color = color; }; const redCar = new Car('red'); // TypeError: Car is not a constructor
調用 new Car('red')
(其中 Car
是箭頭函數)會拋出 TypeError: Car is not a constructor
。
在常規函數的主體內部,arguments
是一個特殊的類似于數組的對象,其中包含被調用函數的參數列表。
讓我們用 3 個參數調用 myFunction
函數:
function myFunction() { console.log(arguments); } myFunction('a', 'b'); // logs { 0: 'a', 1: 'b'}
類似于數組對象的 arguments
中包含調用參數:'a'
和 'b'
。
另一方面,箭頭函數內部未定義 arguments
特殊關鍵字。
用詞法解析 arguments
對象:箭頭函數從外部函數訪問 arguments
。
讓我們試著在箭頭函數內部訪問 arguments
:
function myRegularFunction() { const myArrowFunction = () => { console.log(arguments); } myArrowFunction('c', 'd'); } myRegularFunction('a', 'b'); // logs { 0: 'a', 1: 'b' }
箭頭函數 myArrowFunction()
由參數 'c'
, 'd'
調用。在其主體內部,arguments
對象等于調用 myRegularFunction()
的參數: 'a'
, 'b'
。
如果你想訪問箭頭函數的直接參數,可以使用剩余參數 ...args
:
function myRegularFunction() { const myArrowFunction = (...args) => { console.log(args); } myArrowFunction('c', 'd'); } myRegularFunction('a', 'b'); // logs { 0: 'c', 1: 'd' }
剩余參數 ... args
接受箭頭函數的執行參數:{ 0: 'c', 1: 'd' }
。
使用 return expression
語句從函數返回結果:
function myFunction() { return 42; } myFunction(); // => 42
如果缺少 return
語句,或者 return 語句后面沒有表達式,則常規函數隱式返回 undefined
:
function myEmptyFunction() { 42; } function myEmptyFunction2() { 42; return; } myEmptyFunction(); // => undefined myEmptyFunction2(); // => undefined
可以用與常規函數相同的方式從箭頭函數返回值,但有一個有用的例外。
如果箭頭函數包含一個表達式,而你省略了該函數的花括號,則將顯式返回該表達式。這些是內聯箭頭函數
const increment = (num) => num + 1; increment(41); // => 42
increment()
僅包含一個表達式:num + 1
。該表達式由箭頭函數隱式返回,而無需使用 return
關鍵字。
常規函數是在類上定義方法的常用方式。
在下面 Hero
類中,用了常規函數定義方法 logName()
:
class Hero { constructor(heroName) { this.heroName = heroName; } logName() { console.log(this.heroName); }} const batman = new Hero('Batman');
通常把常規函數用作方法。
有時你需要把該方法作為回調提供給 setTimeout()
或事件監聽器。在這種情況下,你可能會很難以訪問 this
的值。
例如用 logName()
方法作為 setTimeout()
的回調:
setTimeout(batman.logName, 1000); // after 1 second logs "undefined"
1 秒鐘后,undefined
會輸出到控制臺。 setTimeout()
執行 logName
的簡單調用(其中 this
是全局對象)。這時方法會與對象分離。
讓我們手動把 this
值綁定到正確的上下文:
setTimeout(batman.logName.bind(batman), 1000); // after 1 second logs "Batman"
batman.logName.bind(batman)
將 this
值綁定到 batman
實例。現在,你可以確定該方法不會丟失上下文。
手動綁定 this
需要樣板代碼,尤其是在你有很多方法的情況下。有一種更好的方法:把箭頭函數作為類字段。
感謝類字段提案(目前在第3階段),你可以將箭頭函數用作類中的方法。
與常規函數相反,現在用箭頭定義的方法能夠把 this
詞法綁定到類實例。
讓我們把箭頭函數作為字段:
class Hero { constructor(heroName) { this.heroName = heroName; } logName = () => { console.log(this.heroName); } } const batman = new Hero('Batman');
現在,你可以把 batman.logName
用于回調而無需手動綁定 this
。 logName()
方法中 this
的值始終是類實例:
setTimeout(batman.logName, 1000); // after 1 second logs "Batman"
了解常規函數和箭頭函數之間的差異有助于為特定需求選擇正確的語法。
常規函數中的 this
值是動態的,并取決于調用方式。是箭頭函數中的 this
在詞法上是綁定的,等于外部函數的 this
。
常規函數中的 arguments
對象包含參數列表。相反,箭頭函數未定義 arguments
(但是你可以用剩余參數 ...args
輕松訪問箭頭函數參數)。
如果箭頭函數有一個表達式,則即使不用 return
關鍵字也將隱式返回該表達式。
最后一點,你可以在類內部使用箭頭函數語法定義去方法。粗箭頭方法將 this
值綁定到類實例。
不管怎樣調用胖箭頭方法,this
始終等于類實例,在回調這些方法用時非常有用。
看完這篇關于詳解JS箭頭函數和常規函數的文章,如果覺得文章內容寫得不錯的話,可以把它分享出去給更多人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。