在React元件中,通常可通過兩種方式來定義元件的方法:普通函式、箭頭函式;作為方法存在,那麼兩者到底有什麼區別呢?
方法掛載點
es6,有一部分是對過去版本的js進行包裝。在使用es6語法的React元件中,要剖析普通函式和箭頭函式定義方法有什麼區別,可通過babel轉換,轉換成我們熟悉的js語法,看看二者的本來面目。
舉個例子:
class Hello {
greet(){ },
say = () => { },
}
複製程式碼
babel轉換後,突出重點,大致如下:
function Hello(){
this.say = () => { }
}
function.prototype.greet = function() { }
複製程式碼
通過轉義後的程式碼,可看到區別:
-
普通函式被定義為類的原型方法
通過function建立的原型方法。
-
箭頭函式被定義為類的例項方法
通過箭頭方法建立的例項方法。
原型方法和例項方法?
- 屬性查詢 在查詢例項的屬性和方法時,首先會在例項的屬性、方法中查詢,當沒有找到時,在循著例項的原型鏈進行查詢,直到查詢到對應的屬性和和方法,或者最後什麼都查不到。這就和效能相關了,查詢屬性、方法的時間有過不同。
- 呼叫 例項方法只能通過例項呼叫,而原型方法還能通過函式呼叫,比如:A.prototype.click()。
this指向
在es6之前的js語法中,this的指向是一個比較多場景的問題在Js中,在此忽略。我們今天只講在React元件中這兩種方法的this指向。從上面得出,兩個方法的在類中的的掛載點是不同的,然而,這並不是導致他們作為方法,表現差異有所不同的原因,更多的是他們的的建立方式導致this有所區別。
箭頭函式定義的方法
箭頭函式定義方法時,this指向的是函式定義時的作用域。看例子:
function A(){
this.num = 2;
this.handleClick = () => { console.log(this.num) };
}
const B = new A();
// 第一種情況
B.handleClick(); //2
// 第二種情況
const fn = b.handleClick;
fn(); // 2
複製程式碼
普通函式定義的方法
而普通函式的this,卻是根據呼叫它時的物件有所關係。
function A(){
this.num = 2
this.handleClick = function(){console.log(this.num) }
}
const B = new A();
//以下都為嚴格模式下
B.handleHover(); // 2
const fn = B.handleHover;
fn(); // 報錯,因為在嚴格模式下this為undefined
複製程式碼
無論是原型方法或者是例項方法,導致在呼叫時,this不同,原因在於他們的建立方式,當使用箭頭函式建立,那麼this將指向函式定義時的作用域;而當使用普通的function建立時,this的指向和函式的呼叫環境有關,(關於普通函式this的指向有所不瞭解,可通過《你不知道的javascript》熟悉)
所以,無論如何,箭頭函式的this都不會發生改變,this指向的是元件;而普通函式的this隨著呼叫場景的變化有所變化。
方法使用
如果我們在需要將元件的一個方法繫結給一個子元素,為了保證函式中的this指向的是這個React元件(當函式需要藉助元件的一些狀態和屬性時)。
class Hello extends React.PureComponent {
greet() {console.log(this)}
say = () => { console.log(this)}
render() {
return (
<div>
// 普通函式
<div onClIck={this.greet.bind(this)}>普通函式</div>
<div onClick={(e) => this.greet(e)}></div>
// 箭頭函式
<div onClick={this.say}></div>
</div>
)
}
}
複製程式碼
普通函式的傳遞方法視覺上就覺得有點繁瑣,除此之外,更重要的是效能方面。
React的生命週期中,shouldUpdateComponent,當shouldUpdateComponent返回false時,元件將不會重新render,子元件也可避免重新render。在 React 15.3.0 ,Reac可通過React.Purecomponent定義元件,當shouldUpdateComponent進行shallow compare時,避免一些不必要的render。而通過普通函式定義的方法,通過bind繫結後,每次父元件發生render時,方法就得重新bind(this),對於子元件而言,它的props、state發生了改變,則必須發生重新渲染。
如果我們定義的方法不用繫結給子元素,而是被元件自己內部的函式呼叫,箭頭函式和普通函式都可以用來定義方法。
class DownloadGameBtn extends React.PureComponent {
constructor(props) {
super(props);
this.initInfo();
this.initSize();
}
initInfo() {
console.log(this); // 指向DownloadGameBtn元件
}
initSize = () => {
console.log(this) // 指向DownloadGameBtn元件
}
}
複製程式碼
參考
函式作為React元件的方法時, 箭頭函式和普通函式的區別是什麼?
最後
在工作中遇到的問題,通過各種資料查詢,進行總結和歸納,感謝各位前輩的分享。這是第一次在一個公共社群發表自己的總結文章,寫的有點蠢蠢的,希望這些可以幫到和我一樣遇到類似困惑的朋友。然後,大家輕點噴。