1. 程式人生 > >React Native 中 ES6+ 和 ES5 語法比較

React Native 中 ES6+ 和 ES5 語法比較

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`,

參考