ES6 提供了更接近傳統語言的寫法,引入了 Class(類)這個概念,做爲對象的模板。經過class關鍵字,能夠定義類。
基本上,ES6 的class能夠看做只是一個語法糖,它的絕大部分功能,ES5 均可以作到,新的class寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法而已
特色node
1.類的全部方法都定義在類的prototype屬性上面react
class Point { constructor() { // ... } } == Point.prototype = { constructor() {}, };
2.Point.prototype.constructor === Point // true
3.定義「類」的方法的時候,前面不須要加上function這個關鍵字,直接把函數定義放進去了就能夠了
4.類不存在變量提高(hoist),這一點與 ES5 徹底不一樣。
5.類的方法內部若是含有this,它默認指向類的實例
6.若是在一個方法前,加上static關鍵字,就表示該方法不會被實例繼承,而是直接經過類來調用,這就稱爲「靜 態方法」。
7.寫法express
ES5寫法編程
function Point(x, y) { this.x = x; this.y = y; } Point.prototype.toString = function () { return '(' + this.x + ', ' + this.y + ')'; }; var p = new Point(1, 2);
ES6redux
class Point { constructor(x, y) { this.x = x; this.y = y; } toString() { return '(' + this.x + ', ' + this.y + ')'; } }
這是ES6對類的默認方法,經過 new 命令生成對象實例時自動調用該方法。而且,該方法是類中必須有的,若是沒有顯示定義,則會默認添加空的constructor( )方法。
1.constructor方法默認返回實例對象(即this)數組
class Point { constructor(x, y) { this.x = x; this.y = y; } } point.hasOwnProperty('x') // true
2.super( ) ——繼承app
在class方法中,繼承是使用 extends 關鍵字來實現的。子類 必須 在 constructor( )調用 super( )方法,不然新建實例時會報錯。 在 constructor 中必須調用 super 方法,由於子類沒有本身的 this 對象,而是繼承父類的 this 對象 ,而後對其進行加工,而 super 就表明了父類的構造函數。super 雖然表明了父類 A 的構造函數, 可是返回的是子類 B 的實例,即 super 內部的 this 指的是 B,所以 super() 在這裏至關於 A.prototype.constructor.call(this, props)。 class A {} class B extends A { constructor() { super(); // ES6 要求,子類的構造函數必須執行一次 super 函數,不然會報錯。 } }
3.若是你在constructor中要使用this.props,就必須給super加參數:super(props);函數
順帶一提的是,其實能夠給組件標籤也加上 refui
<input ref={(input) => this.input = input} />//input爲獲取的節點
嵌套的結構在組件內部均可以經過 props.children 獲取到 class Card extends Component { render () { return ( <div className='Card'> <div className='0'> {this.props.children[0]} </div> <div className='1'> {this.props.children[1]} </div> </div> ) } } ReactDOM.render( <Card> <div>children[0]</div> <div>children[1]</div> </Card>, document.getElementById('root') )
class LikeButton extends Component { static defaultProps = { likedText: '取消', unlikedText: '點贊' } static propTypes = { comment: PropTypes.object//const { comment } = this.props } static propTypes = { comment: PropTypes.object.isRequired } }
bind返回值是由指定的this值和初始化參數改造的原函數拷貝
在JSX中傳遞的事件不是一個字符串,而是一個函數(如:onClick={this.handleClick}),此時onClick便是中間變量,因此處理函數中的this指向會丟失。解決這個問題就是給調用函數時bind(this),從而使得不管事件處理函數如何傳遞,this指向都是當前實例化對象。
固然,若是不想使用bind(this),咱們能夠在聲明函數時使用箭頭函數將函數內容返回給一個變量,並在調用時直接使用this.變量名便可
1 <button onClick={this.handleClick.bind(this)}>有bind點擊一下</button> 2 constructor(props) { super(props); this.state = { }; this.handleClick=this.handleClick.bind(this) } 3 <button onClick={()=>{this.handleClick()}>
高階組件是一個函數(而不是組件),它接受一個組件做爲參數,返回一個新的組件。這個新的組件會使用你傳給它的組件做爲子組件
import React, { Component } from 'react' export default (WrappedComponent, name) => { class NewComponent extends Component { constructor () { super() this.state = { data: null } } componentWillMount () { let data = localStorage.getItem(name) this.setState({ data }) } render () { return <WrappedComponent data={this.state.data} /> } } return NewComponent }
import wrapWithLoadData from './wrapWithLoadData' class InputWithUserName extends Component { render () { return <input value={this.props.data} /> } } InputWithUserName = wrapWithLoadData(InputWithUserName, 'username') export default InputWithUserName
模塊功能主要由兩個命令構成:export和import。export命令用於規定模塊的對外接口,import命令用於輸入其餘模塊提供的功能。一個模塊就是一個獨立的文件。該文件內部的全部變量,外部沒法獲取。若是你但願外部可以讀取模塊內部的某個變量,就必須使用export關鍵字輸出該變量
1.export命令規定的是對外的接口,必須與模塊內部的變量創建一一對應關係
2.export語句輸出的接口,與其對應的值是動態綁定關係,即經過該接口,能夠取到模塊內部實時的值
3.注意輸出時{}的使用代表其是一個接口,不用則爲值會報錯this
//export var year = 1958; var firstName = 'Michael'; var lastName = 'Jackson'; var year = 1958; export {firstName, lastName, year}; ---------- // 報錯 export 1; // 報錯 var m = 1; export m; ---------- // 寫法一 export var m = 1; // 寫法二 var m = 1; export {m}; // 寫法三 var n = 1; export {n as m}; //函數 function f() {} export {f};
4.import命令接受一對大括號,裏面指定要從其餘模塊導入的變量名。大括號裏面的變量名,必須與被導入模塊(profile.js)對外接口的名稱相同
5.若是想爲輸入的變量從新取一個名字,import命令要使用as關鍵字,將輸入的變量重命名
6.import命令輸入的變量都是隻讀的,由於它的本質是輸入接口。也就是說,不容許在加載模塊的腳本里面,改寫
接口
7.注意,import命令具備提高效果,會提高到整個模塊的頭部,首先執行
8.import是靜態執行,因此不能使用表達式和變量
import { lastName as surname } from './profile.js'; import {myMethod} from 'util';//util是模塊文件名,必須經過配置,告訴引擎怎麼取到這個模塊 import 'lodash';//import語句會執行所加載的模塊
除了指定加載某個輸出值,還可使用總體加載,即用星號(*)指定一個對象,全部輸出值都加載在這個對象上面。
// circle.js export function area(radius) { return Math.PI * radius * radius; } export function circumference(radius) { return 2 * Math.PI * radius; }
import * as circle from './circle'; console.log('圓面積:' + circle.area(4)); console.log('圓周長:' + circle.circumference(14));
// export-default.js export default function () { console.log('foo'); } // import-default.js import customName from './export-default'; customName(); // 'foo'
1.使用export default時,對應的import語句不須要使用大括號
// 第一組 export default function crc32() { // 輸出 // ... } import crc32 from 'crc32'; // 輸入 // 第二組 export function crc32() { // 輸出 // ... }; import {crc32} from 'crc32'; // 輸入 //結合使用 import _, { each, forEach } from 'lodash';
2.export default命令其實只是輸出一個叫作default的變量,因此它後面不能跟變量聲明語句
// 正確 export var a = 1; // 正確 var a = 1; export default a; // 錯誤 export default var a = 1;
本質上,這種寫法屬於「模式匹配」,只要等號兩邊的模式相同,左邊的變量就會被賦予對應的值。下面是一些使用嵌套數組進行解構的例子
let [foo, [[bar], baz]] = [1, [[2], 3]]; foo // 1 bar // 2 baz // 3 let [ , , third] = ["foo", "bar", "baz"]; third // "baz" let [x, , y] = [1, 2, 3]; x // 1 y // 3 let [head, ...tail] = [1, 2, 3, 4]; head // 1 tail // [2, 3, 4] let [x, y, ...z] = ['a']; x // "a" y // undefined z // []
1.若是等號的右邊不是數組(或者嚴格地說,不是可遍歷的結構,參見《Iterator》一章),那麼將會報錯
// 報錯 let [foo] = 1; let [foo] = false; let [foo] = NaN;
2.解構賦值容許指定默認值
let [foo = true] = []; foo // true let [x, y = 'b'] = ['a']; // x='a', y='b' let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
3.解構不只能夠用於數組,還能夠用於對象
//簡易模型 let { bar, foo } = { foo: "aaa", bar: "bbb" }; foo // "aaa" bar // "bbb" let { baz } = { foo: "aaa", bar: "bbb" }; baz // undefined
//基本模型 var robotA = { name: "Bender" }; var robotB = { name: "Flexo" }; var { name: nameA } = robotA; var { name: nameB } = robotB; nameA//"Bender" nameB//"Flexo"
//多重解構 const node = { loc: { start: { line: 1, column: 5 } } }; let { loc, loc: { start }, loc: { start: { line }} } = node; line // 1 loc // Object {start: Object} start // Object {line: 1, column: 5}
//默認值 var {x, y = 5} = {x: 1}; x // 1 y // 5 var { message: msg = "Something went wrong" } = {};
//JavaScript 引擎會將{x}理解成一個代碼塊,從而發生語法錯誤 //只有不將大括號寫在行首,避免 JavaScript 將其解釋爲代碼塊,才能解決這個問題 let x; ({x} = {x: 1});
//字符解構 const [a, b, c, d, e] = 'hello'; a // "h" b // "e" c // "l" d // "l" e // "o"
箭頭函數沒有 this,因此須要經過查找做用域鏈來肯定 this 的值。這就意味着若是箭頭函數被非箭頭函數包含,this 綁定的就是最近一層非箭頭函數的 this。
沒有 arguments
不能經過 new 關鍵字調用
沒有原型
沒有 super
格式1:多個參數 (param1, param2, …, paramN) => { statements } // statements應該有return 語句 (param1, param2, …, paramN) => expression //至關於 return expression 格式2:一個參數 (singleParam) => { statements } singleParam => { statements } //能夠去掉括號 格式3:沒有參數 () => { statements } 格式4:返回對象 params => ({foo: bar}) 格式5:支持擴展符號 (param1, param2, ...rest) => { statements } 格式6:支持默認值 (param1 = defaultValue1, param2, …, paramN = defaultValueN) => { statements } 格式7:支持解構賦值 var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c; f(); // 6
修飾器是一個對類進行處理的函數。修飾器函數的第一個參數,就是所要修飾的目標類。@是語法糖
1.類的修飾
function decorator(target) { target.isTestable = true; } @decorator class A {} // 等同於 class A {} A = decorator(A) || A; A.isTestable//true
2.修飾器帶參數
function testable(isTestable) { return function(target) { target.isTestable = isTestable; } } @testable(true) class MyTestableClass {} MyTestableClass.isTestable // true
3.與redux庫結合
class MyReactComponent extends React.Component {} export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent); //connect(mapStateToProps, mapDispatchToProps)返回一個函數 //加上()即(MyReactComponent),再次執行函數,傳入一個組件返回一個被修飾的組件 == @connect(mapStateToProps, mapDispatchToProps)//將props導入到被修飾的組件上去 export default class MyReactComponent extends React.Component {}