《深刻理解ES6》筆記—— JavaScript中的類class(9)

ES5中的近類結構

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 class類

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]

Symbol.species

該用法我尚未接觸過,目前只知道在內建對象中使用了該方法,若是在類中調用this.constructor,使用Symbol.species可讓派生類重寫返回類型。

在構造函數中使用new.target

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來練練手了。

=> 返回文章目錄

相關文章
相關標籤/搜索