ES6之箭頭函數深入理解


相對於普通函數的區別

新的書寫方式 

this 的改變

不能當構造函數

沒有 prototype 屬性

沒有 arguments 對象

 

新的書寫方式

書寫方式很簡單!直接看下圖,

常規方式寫一個函數
const fun = function(number){ return number * 2 }
 
使用箭頭函數
const fun = (number) => { return number * 2 }
 
如果只有一個參數,還可以省略前面的小括號
const fun = number => { return number * 2 }
 
如果只有一條執行語句,甚至可以省略后面的大括號,而且可以也不能寫 return
const fun = number => number * 2 
 
也可以寫成立即執行函數
const fun = (() => 3 * 2)()  // 6

 

this的改變

執行上下文

討論箭頭函數的 this 之前,不得不再熟悉一下 執行上下文(Execution Context),因為 this 指針(this value) 就存儲在執行上下文中。

執行上下文保存着函數執行所需的重要信息,其中有三個屬性:變量對象(variable object),作用域鏈(scope chain),this指針(this value),它們影響着變量的解析、變量作用域、函數 this 的指向。執行上下文分為 全局執行上下文函數執行上下文

全局代碼開始執行前,會以 window 為目標產生一個全局執行上下文, 開始對代碼預編譯,這時候 this 指向的就是 window,接着開始執行全局代碼。

當函數代碼開始執行前,會以函數為目標產生一個函數執行上下文,開始對該函數預編譯,這時候 this 的指向要分幾種情況(下面討論),接着開始執行函數代碼,函數代碼執行完后函數執行上下文就被會刪除。多個函數會產生多個執行上下文。

上面說到函數預編譯的 this 分下面四種情況:

第一種: 函數自主調用 如 fun() 或者是 普通的立即執行函數(區別於箭頭函數方式的立即執行函數), this 指向 window

第二種: 函數被調用,當函數被某個對象調用時,函數產生的執行上下文中的 this 指向 該對象

第三種: 通過 call() apply() bind() 方法改變 this,this 指向被傳入的 第一個參數

第四種: 在構造函數中,this 指向被創建的 實例

由於箭頭函數是不能通過 call() apply() bind() 方法改變 this,也不能當做構造函數,所以接下來只演示第一和第二種情況的代碼

var a = { origin: 'a', b: { origin: 'b', show: function(){     var origin = 'show'; console.log(this.origin);   } } } var origin = 'window' a.b.show(); // 因為 b 對象調用了 show 函數,所以 show 函數的執行上下文中的 this 指針指向 b 對象
var fun = a.b.show;     // 注意這里是將 show 函數賦值給fun,相當於 var fun = function(){console.log(this)}
fun();      // 因為 fun 是自主調用,所以 this 指針指向 window,自然就打印 window 對象了

可能有人會有這個疑惑:a.b.show() 中,a 調用了 b,是不是 b 的 this 指向 a 了?

前面也說到了,this 儲存在執行上下文中,而只有 全局 和 函數 才會產生執行上下文,在執行上下文里記錄着 this,而 b 是全局中 a 對象里面的一個對象,不存在誰調用它,它的 this 就是誰的說法。

接下來理解箭頭函數中的 this 就非常容易了。

箭頭函數中的 this

首先,箭頭函數不會創建自己的 this,它只會從自己的作用域鏈上找父級執行上下文的 this,而不是誰調用它,它的 this 就是誰。所以箭頭函數中的 this,取決於你上層執行上下文的 this 。

下例中,

obj 分別調用了 show1 和 show2 兩個方法,所以show1 和 show2 中的 this 都是指向 obj,

show1 中, setTimeout 里面是箭頭函數,從作用域鏈中找到 show1 中的 this,所以它的 this 就是 obj 對象;

show2 中,setTimeout 里面的函數換成普通函數,函數自主調用,所以他的 this 就是 window 對象

var id = 0; var obj = { id: 1, show1: function(){ setTimeout(() => { console.log(this.id) }, 1000) },   show2: function(){     setTimeout(function(){       console.log(this.id)     }, 2000)   } } obj.show1(); // 打印 1
obj.show2();    // 打印 0

 

不能當成構造函數

var Foo = () => {}; var foo = new Foo(); // TypeError: Foo is not a constructor

 

沒有 prototype 屬性

var Foo = () => {}; console.log(Foo.prototype); // undefined

 

沒有 arguments 對象

在大多數情況下,使用' ... ' 運算符是比使用 arguments 對象的更好選擇。

function foo(...arg) { 
  return arg; 
}
foo(1, 2, 3, 4); // 1
function foo(...numbers) { 
    numbers.forEach((number)=>{
        console.log(number);
    })
} 
foo(1, 2, 3, 4);  // 1 2 3 4

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM