ES5以及以前的版本,沒有類的概念,可是聰明的JavaScript開發者,爲了實現面向對象,建立了特殊的近類結構。java
ES5中建立類的方法:新建一個構造函數,定義一個方法而且賦值給構造函數的原型。react
'use strict'; //新建構造函數,默認大寫字母開頭 function Person(name) { this.name = name; } //定義一個方法而且賦值給構造函數的原型 Person.prototype.sayName = function () { return this.name; }; var p = new Person('eryue'); console.log(p.sayName() // eryue );
ES6實現類很是簡單,只須要類聲明。推薦 babel在線測試ES6 測試下面的代碼。segmentfault
若是你學過java,那麼必定會很是熟悉這種聲明類的方式。babel
class Person { //新建構造函數 constructor(name) { this.name = name //私有屬性 } //定義一個方法而且賦值給構造函數的原型 sayName() { return this.name } } let p = new Person('eryue') console.log(p.sayName()) // eryue
和ES5中使用構造函數不一樣的是,在ES6中,咱們將原型的實現寫在了類中,但本質上仍是同樣的,都是須要新建一個類名,而後實現構造函數,再實現原型方法。函數
私有屬性:在class中實現私有屬性,只須要在構造方法中定義this.xx = xx。測試
一、函數聲明能夠被提高,類聲明不能提高。ui
二、類聲明中的代碼自動強行運行在嚴格模式下。this
三、類中的全部方法都是不可枚舉的,而自定義類型中,能夠經過Object.defineProperty()手工指定不可枚舉屬性。lua
四、每一個類都有一個[[construct]]的方法。prototype
五、只能使用new來調用類的構造函數。
六、不能在類中修改類名。
類有2種表現形式:聲明式和表達式。
//聲明式 class B { constructor() {} } //匿名錶達式 let A = class { constructor() {} } //命名錶達式,B能夠在外部使用,而B1只能在內部使用 let B = class B1 { constructor() {} }
JavaScript函數是一等公民,類也設計成一等公民。
一、能夠將類做爲參數傳入函數。
//新建一個類 let A = class { sayName() { return 'eryue' } } //該函數返回一個類的實例 function test(classA) { return new classA() } //給test函數傳入A let t = test(A) console.log(t.sayName()) // eryue
二、經過當即調用類構造函數能夠建立單例。
let a = new class { constructor(name) { this.name = name } sayName() { return this.name } }('eryue') console.log(a.sayName()) // eryue
類支持在原型上定義訪問器屬性。
class A { constructor(state) { this.state = state } // 建立getter get myName() { return this.state.name } // 建立setter set myName(name) { this.state.name = name } } // 獲取指定對象的自身屬性描述符。自身屬性描述符是指直接在對象上定義(而非從對象的原型繼承)的描述符。 let desriptor = Object.getOwnPropertyDescriptor(A.prototype, "myName") console.log("get" in desriptor) // true console.log(desriptor.enumerable) // false 不可枚舉
可計算成員是指使用方括號包裹一個表達式,以下面定義了一個變量m,而後使用[m]設置爲類A的原型方法。
let m = "sayName" class A { constructor(name) { this.name = name } [m]() { return this.name } } let a = new A("eryue") console.log(a.sayName()) // eryue
回顧一下上一章講的生成器,生成器是一個返回迭代器的函數。在類中,咱們也可使用生成器方法。
class A { *printId() { yield 1; yield 2; yield 3; } } let a = new A() console.log(a.printId().next()) // {done: false, value: 1} console.log(a.printId().next()) // {done: false, value: 2} console.log(a.printId().next()) // {done: false, value: 3}
這個寫法頗有趣,咱們新增一個原型方法稍微改動一下。
class A { *printId() { yield 1; yield 2; yield 3; } render() { //從render方法訪問printId,很熟悉吧,這就是react中常常用到的寫法。 return this.printId() } } let a = new A() console.log(a.render().next()) // {done: false, value: 1}
靜態成員是指在方法名或屬性名前面加上static關鍵字,和普通方法不同的是,static修飾的方法不能在實例中訪問,只能在類中直接訪問。
class A { constructor(name) { this.name = name } static create(name) { return new A(name) } } let a = A.create("eryue") console.log(a.name) // eryue let t = new A() console.log(t.create("eryue")) // t.create is not a function
咱們在寫react的時候,自定義的組件會繼承React.Component。
class A extends Component { constructor(props){ super(props) } }
A叫作派生類,在派生類中,若是使用了構造方法,就必須使用super()。
class Component { constructor([a, b] = props) { this.a = a this.b = b } add() { return this.a + this.b } } class T extends Component { constructor(props) { super(props) } } let t = new T([2, 3]) console.log(t.add()) // 5
關於super使用的幾點要求:
一、只能夠在派生類中使用super。派生類是指繼承自其它類的新類。
二、在構造函數中訪問this以前要調用super(),負責初始化this。
class T extends Component { constructor(props) { this.name = 1 // 錯誤,必須先寫super() super(props) } }
三、若是不想調用super,可讓類的構造函數返回一個對象。
咱們能夠在繼承的類中重寫父類的方法。
class Component { constructor([a, b] = props) { this.a = a this.b = b } //父類的add方法,求和 add() { return this.a + this.b } } class T extends Component { constructor(props) { super(props) } //重寫add方法,求積 add() { return this.a * this.b } } let t = new T([2, 3]) console.log(t.add()) // 6
父類中的靜態成員,也能夠繼承到派生類中。靜態成員繼承只能經過派生類訪問,不能經過派生類的實例訪問。
class Component { constructor([a, b] = props) { this.a = a this.b = b } static printSum([a, b] = props) { return a + b } } class T extends Component { constructor(props) { super(props) } } console.log(T.printSum([2, 3])) // 5
很好理解,就是指父類能夠是一個表達式。
有些牛逼的人以爲使用內建的Array不夠爽,就但願ECMA提供一種繼承內建對象的方法,而後那幫大神們就把這個功能添加到class中了。
class MyArray extends Array { } let colors = new Array() colors[0] = "1" console.log(colors) // [1]
該用法我尚未接觸過,目前只知道在內建對象中使用了該方法,若是在類中調用this.constructor,使用Symbol.species可讓派生類重寫返回類型。
new.target一般表示當前的構造函數名。一般咱們使用new.target來阻止直接實例化基類,下面是這個例子的實現。
class A { constructor() { //若是當前的new.target爲A類,就拋出異常 if (new.target === A) { throw new Error("error haha") } } } let a = new A() console.log(a) // error haha
本章只有一個知識點,那就是class的使用,最開始的聲明class,到後面的繼承派生類,都是很是經常使用的寫法,還有靜態成員的使用。
若是上面的那些例子你練習的不夠爽,或許你該找個react基礎demo簡單的使用class來練練手了。