React: ES5 和 ES6 比較
React 同時支援 ES5 和 ES6 兩種語法。通過 Babel 可以編譯 ES 6 和 JSX , 把他們轉譯成 ES 5 。
今早發現 ES 7都已經正式納入標準了, ES 真是當之無愧程式語言中的“標準帝”。伴隨著學習和使用經驗, ,也用到了一些 ES 7 的語法,這裡主要對React 中 ES5 和 ES6 兩種語法做一個對比和歸納。
createClass vs class
首先上程式碼,直觀感受一下同一個 component 元件使用 ES5 和 ES6 兩種不同的語法寫出的程式碼。
var InputControlES5 = React.createClass({
propTypes: {
initialValue: React.PropTypes.string
},
defaultProps: {
initialValue: ''
},
// Set up initial state
getInitialState: function() {
return {
text: this.props.initialValue || 'placeholder'
};
},
handleChange: function(event) {
this.setState({
text: event.target.value
});
},
render: function() {
return (
<div>
Type something:
<input onChange={this.handleChange}
value={this.state.text} />
</div>
);
}
});
class InputControlES6 extends React.Component {
constructor(props) {
super (props);
// Set up initial state
this.state = {
text: props.initialValue || 'placeholder'
};
// Functions must be bound manually with ES6 classes
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({
text: event.target.value
});
}
render() {
return (
<div>
Type something:
<input onChange={this.handleChange}
value={this.state.text} />
</div>
);
}
}
InputControlES6.propTypes = {
initialValue: React.PropTypes.string
};
InputControlES6.defaultProps = {
initialValue: ''
};
主要區別:
函式繫結:
ES 5 中的 createClass 沒有函式 this 繫結問題的困擾。每個 property 屬性上的函式都自動繫結,通過 this.functionName 就能refer 到函式, 在呼叫函式時 this 能夠正確正確地指向。在 ES 6 寫法中, 函式卻沒有自動繫結, 只能通過手動繫結完成。 解決辦法有以下幾種:
最佳的辦法是在 constructor 中完成, 栗子如上程式碼。
還用現成的一些 npm 包可以幫我們輕鬆搞定, 比如 react-autobind 和 autobind-decorator
除此之外,還可以在 render 方法中內聯繫結:
// Use `.bind`:
render() {
return (
<input onChange={this.handleChange.bind(this)}
value={this.state.text} />
);
}
// --- OR ---
// Use an arrow function:
render() {
return (
<input onChange={() => this.handleChange()}
value={this.state.text} />
);
}
箭頭函式可以解決 this 繫結問題。但這兩種方法效率不如第一種, 每次 render 呼叫的時候,都會建立一個新函式。
- 最後一種方法就是直接使用箭頭函式重寫原來的函式。
// the normal way
// requires binding elsewhere
handleChange(event) {
this.setState({
text: event.target.value
});
}
// the ES7 way
// all done, no binding required
handleChange = (event) => {
this.setState({
text: event.target.value
});
}
直接用箭頭函式寫原來的函式方法, 自動完成了 this 繫結的任務, 函式內的 this 指向 component 元件。但這種寫法尚處於試驗階段, 目前還不是官方 ES 6 中的內容。不過,利用 Babel , 可以放心使用這個方法。
Constructor 建構函式應該呼叫 super
ES6 中的 constructor 需要以 props 作為引數, 並呼叫 super(props) 。 ES 5 的寫法中沒有這一步。
- class 和 createClass
建立類的方式不同: ES 5 中使用 React.createClass , ES 6 中通過 class extends React.Component 實現。import React, {Component} from ‘react’
ES 6 的寫法在同一個檔案中有多個 components 時非常方便其他檔案 import引用。
- 初始 state 狀態的設定
ES 5 中 React.createClass 裡面有一個 initialState 函式, 在每次 component 元件掛載 mount 時候都會被呼叫。
ES 6 的 class 中使用 constructor , 然後呼叫 super , 接著直接設定 state。
- propTypes 屬性型別和 defaultProPs 預設屬性
ES 5 中 React.createClass 在傳入的物件上定義了propTypes 屬性型別和 defaultProPs 預設屬性。
ES 6 的 class 中, propTypes 屬性型別和 defaultProPs 預設屬性成為了 class 本身的 properties 屬性, 所以需要在 class 定義之後才能定義。
利用 ES 7, 可以更方便的完成屬性型別和屬性預設值的設定。
class Person extends React.Component { static propTypes = { name: React.PropTypes.string, age: React.PropTypes.string }; static defaultProps = { name: '', age: -1 }; ... }
參考: