JS 更新快,是以基于 JS 的 RN 文法更新也挺大。在閱讀别人代碼或項目開發時經常會碰到 EMACScript 新舊格式文法寫的程式,給我們的了解造成困擾。是以總結了一些新舊 JS 文法的對比。
1. 子產品
1.1 引用
ES5 中,通過 require 引入外部子產品(相當于 C 中的 #include
1.2 導出單個類
ES5 中,通過 module.exports 導出某個類給别的子產品用
var ES5Syntax = React.createClass({
...
});
module.exports = ES5Syntax;
ES6 中,通過 export default 導出單個類
export default class ES6Syntax extends Component {
...
};
2. 元件
2.1 定義元件
ES5 中,通過React.createClass來定義一個元件類
var ES5Syntax = React.createClass({
render: function() {
return (
<View style={styles.container}>
... // View 的子元件寫在該處
</View>
<View /> // 沒有子元件可以寫為一行
);
},
});
ES6 中,通過定義一個繼承自React.Component的class來定義一個元件類
export default class ES6Syntax extends Component {
render() {
return (
<View />
);
}
}
2.2 定義元件方法
ES5 中,元件方法定義為
functionName: function(param1, ...) {...},
,定義屬性的标準寫法,屬性之間用逗号
,
隔開,方法也是屬性。
var ES5Syntax = React.createClass({
componentWillMount: function(){
},
render: function() {
return (
<View />
);
},
});
ES6 中,元件方法定義為
functionName(param1, ...) {...}
方法之間沒有逗号分隔。
export default class ES6Syntax extends Component {
compoentWillMount() {
}
render() {
return (
<View />
);
}
}
2.3 定義元件的屬性類型和預設屬性
ES5 中,屬性類型和預設屬性分别通過 propTypes 成員和 getDefaultProps 方法來實作。由于 JS 是極弱類型語言,指派的資料類型不同,變量的類型也會随之改變,比如初始為 number 類型的變量居然可以用 string 類型指派。。。,是以就需要對傳入或指派的資料進行類型規範,便于資料有效性檢查。注意:資料有效性檢查隻在開發時候有用。
var ES5Syntax = React.createClass({
getDefaultProps: function() {
return {
name: 'ES5Syntax',
year: 2014,
label: 'ClickMe',
};
},
propTypes: {
name: React.PropTypes.string.isRequired,
year: React.PropTypes.number.isRequired, // isRequired:本屬性必須被包含,否則會産生 warning
label: React.PropTypes.string
},
render: function() {
return (
<View />
);
},
});
ES6+ 中,屬性類型和屬性預設值屬于類本身的靜态屬性,是以可以用 static 成員來實作
export default class ES6Syntax extends Component {
static defaultProps = {
name: 'ES6Syntax',
year: 2015,
label: 'ClickMe',
}; // 注意這裡有分号,用 `class` 定義的類内部的屬性需要用分号 `;` 間隔開,方法不需要。
static propTypes = {
name: React.PropTypes.string.isRequired,
year: React.PropTypes.number.isRequired,
label: React.PropTypes.string.isRequired,
}; // 注意這裡有分号
render: function() {
return (
<View />
);
},
});
2.4 初始化元件的 state
ES5 中,跟屬性初始化類似
var ES5Syntax = React.createClass({
getInitialState: function() {
return {
esVersion: `${this.props.name} v1.0`,
clickCounts: 0,
};
},
});
ES6 中,有兩種寫法
export default class ES6Syntax extends Component {
state = {
esVersion: `${this.props.name} v1.0`,
clickCounts: 0,
};
});
在構造函數中對 state 進行初始化(推薦這種方法)
export default class ES6Syntax extends Component {
constructor(props) {
super(props);
// Operations usually carried out in componentWillMount go here
this.state = {
esVersion: `${this.props.name} v1.0`,
clickCounts: 0,
};
};
};
3. 将方法作為回調函數/胖箭頭函數 =>
=>
ES5 中,React.createClass 會把所有的方法都 bind 一遍,這樣可以送出到任意的地方作為回調函數,而this不會變化。但官方現在逐漸認為這反而是不标準、不易了解的。
var ES5Syntax = React.createClass({
buttonClick: function(e) {
// Here, 'this' refers to the component instance.
this.setState({clickCounts: this.state.clickCounts + 1});
},
render: function() {
return (
<View style={styles.container}>
<TouchableHighlight onPress={this.buttonClick}>
<Text>{this.props.label}</Text>
</TouchableHighlight>
</View>
);
},
});
在ES6下,你需要通過bind來綁定this引用,或者使用箭頭函數(它會綁定目前scope的this引用)來調用
// 方法1. 在 constructor 中手動綁定
export default class ES6Syntax extends Component {
constructor(props) {
super(props);
this.buttonClick = this.buttonClick.bind(this);
this.state = {
esVersion: `${this.props.name} v1.0`,
clickCounts: 0,
};
// Operations usually carried out in componentWillMount go here
};
buttonClick(e) {
this.setState({clickCounts: this.state.clickCounts + 1});
}
render() {
return (
<View style={styles.container}>
<TouchableHighlight
onPress={this.buttonClick}>
<Text>{this.props.label}</Text>
</TouchableHighlight>
</View>
);
}
}
// 方法2. 利用箭頭函數自動綁定
export default class ES6Syntax extends Component {
buttonClick = (e) => {
// Here, 'this' refers to the component instance.
this.setState({clickCounts: this.state.clickCounts + 1});
// this.state.clickCounts += 1; // state 必須用 this.setState() 修改
}; // 注意這裡有分号
render() {
return (
<View style={styles.container}>
<TouchableHighlight
onPress={this.buttonClick}>
<Text>{this.props.label}</Text>
</TouchableHighlight>
</View>
);
}
}
箭頭函數實際上是在這裡定義了一個臨時的函數,箭頭函數的箭頭
=>
之前是一個空括号、單個的參數名、或用括号括起的多個參數名,而箭頭之後可以是一個表達式(作為函數的傳回值),或者是用花括号括起的函數體(需要自行通過return來傳回值,否則傳回的是undefined)
4. Rest & Spread 運算符: ...
...
Rest 剩餘參數運算符,在函數被調用時,剩餘參數表示為一個數組名,該數組包含了那些沒有對應形參的,長度不确定的剩餘實參
Spread 展開運算符可以将一個可疊代的對象在函數調用的位置展開成為多個參數,或者在數組字面量中展開成多個數組元素.
Rest 将多個參數壓縮為一個數組,Spread 是 Rest 的逆操作,将一個”數組内的元素”展開。
可以利用 Rest & Spread 運算符一次擷取或者傳遞 N 個特定的 props
class CustomText extends Component {
render() {
var {
className,
...otherProps,
} = this.props; // ...otherProps: 擷取除 className 外所有的其他的 props
return (
<Text {...otherProps}>{className}</Text> // 向 Text 傳遞所有otherProps 包含的 props
)
}
}
5. template strings
ES6 中引入了 template strings (模闆字元串),允許嵌入表達式,并且支援多行字元串和字元串插補特性。模闆字元串使用反引号 (
) 來代替普通字元串中的用雙引号和單引号。模闆字元串可以包含特定文法(${expression})的占位符,占位符内可以含有表達式,類比 swift 中的占位符 (expression)。 template strings 使得字元串操作更為友善、簡潔。
ES5 中
esVersion: this.props.name + " v1.0",
ES6 中
esVersion: `${this.props.name} v1.0`,
參考
- React/React Native 的ES5 ES6寫法對照表
- React on ES6+
- 本文執行個體代碼: https://github.com/adispring/ES5_ES6_On_RN