最近翻譯了一篇關於 this 的文章,不少人評價不錯,可是原文沒有講到箭頭函數的 this
,因此我來補充一篇文章來專門講解。瀏覽器
箭頭函數是 ES6 添加的新語法,基礎知識就很少介紹了,下面咱們來說一講箭頭函數的 this
怎麼指向。bash
在以往的函數中,this
有各類各樣的指向(隱式綁定,顯示綁定,new 綁定, window 綁定......),雖然靈活方便,但因爲不能在定義函數時而直到實際調用時才能知道 this
指向,很容易給開發者帶來諸多困擾。閉包
假如咱們有下面這段代碼(本文代碼都是在瀏覽器下運行),app
function User() {
this.name = 'John';
setTimeout(function greet() {
console.log(`Hello, my name is ${this.name}`); // Hello, my name is
console.log(this); // window
}, 1000);
}
const user = new User();
複製代碼
greet
裏的 this
能夠由上一篇文章的四個規則判斷出來。對,由於沒有顯示綁定、隱式綁定或 new
綁定、因此直接得出結論 this
指向 window
。但實際上咱們想把 this
指向 user
對象!函數
之前是怎麼解決的呢?看下面的代碼:post
1. 使用閉包ui
function User() {
const self = this;
this.name = 'John';
setTimeout(function greet() {
console.log(`Hello, my name is ${self.name}`); // Hello, my name is John
console.log(self); // User {name: "John"}
}, 1000);
}
const user = new User();
複製代碼
2. 使用顯示綁定 — bind
this
function User() {
this.name = 'John';
setTimeout(function greet() {
console.log(`Hello, my name is ${this.name}`); // Hello, my name is John
console.log(this); // User {name: "John"}
}.bind(this)(), 1000);
}
const user = new User();
複製代碼
3. 利用 setTimeout
的能夠傳更多參數的特性spa
其實第三種和第一種比較像,都用到了閉包。翻譯
function User() {
this.name = 'John';
setTimeout(function greet(self) {
console.log(`Hello, my name is ${self.name}`); // Hello, my name is John
console.log(self); // User {name: "John"}
}, 1000, this);
}
const user = new User();
複製代碼
三種方法均可以解決問題,可是都要額外寫冗餘的代碼來指定 this
。
如今,箭頭函數(Arrow Function)正是 ES6 引入來解決這個問題的,它能夠輕鬆地讓 greet
函數保持 this
指向 user
對象。
下面是箭頭函數版本:
function User() {
this.name = 'John';
setTimeout(() => {
console.log(`Hello, my name is ${this.name}`); // Hello, my name is John
console.log(this); // User {name: "John"}
}, 1000);
}
const user = new User();
複製代碼
完美,直接把普通函數改爲箭頭函數就能解決問題。
箭頭函數在本身的做用域內不綁定 this
,即沒有本身的 this
,若是要使用 this
,就會指向定義時所在的做用域的 this
值。在上面的代碼中即指向 User
函數的 this
,而 User 函數經過 new
綁定,因此 this
實際指向 user
對象。
若是上述代碼在嚴格模式下運行會有影響嗎?
function User() {
this.name = 'John';
setTimeout(() => {
'use strict'
console.log(`Hello, my name is ${this.name}`); // Hello, my name is John
console.log(this); // User {name: "John"}
}, 1000);
}
const user = new User();
複製代碼
答案是沒有影響。由於箭頭函數沒有本身的 this
,它的 this
來自於 User
的 this
,只要 User
的 this
不變,箭頭函數的 this
也保持不變。
那麼使用 bind
,call
或者 apply
呢?
function User() {
this.name = 'John';
setTimeout((() => {
console.log(`Hello, my name is ${this.name}`); // Hello, my name is John
console.log(this); // User {name: "John"}
}).bind('no body'), 1000);
}
const user = new User();
複製代碼
答案仍是沒有影響。由於箭頭函數沒有本身的 this
,使用 bind
,call
或者 apply
時,箭頭函數會自動忽略掉 bind
的第一個參數,即 thisArg
。
總結:箭頭函數在本身的做用域內沒有本身的 this
,若是要使用 this
,就會指向定義時所在的做用域的 this
值。
歡迎在下方評論交流哦!