ES6—class與面向對象編程(8)

在ES5中,咱們常用方法或者對象去模擬類的使用,並基於原型實現繼承,雖然能夠實現功能,可是代碼並不優雅,不少人仍是傾向於用 class 來組織代碼,不少類庫、框架創造了本身的 API 來實現 class 的功能。javascript

ES6 時代終於有了 class (類)語法,能讓咱們能夠用更簡明的語法實現繼承,也使代碼的可讀性變得更高,同時爲之後的JavaScript語言版本添加更多的面向對象特徵打下基礎。有了ES6的class 之後媽媽不再用擔憂咱們的代碼亂七八糟了,這簡直是喜大普奔的事情。ok,咱們看看神奇的class.java

1、 類的定義程序員

1.1 ES5 模擬類定義編程

function Person( name , age ) {
    this.name = name;
    this.age = age;
}
Person.prototype.say = function(){
    return '我叫' + this.name + ',今年' + this.age + '歲';
}
var  p = new Person('大彬哥',18);  // Person {name: "大彬哥", age: 18}
p.say()                           //"我叫大彬哥,今年18歲"

使用ES5語法定義了一個Person類,該類有name和age兩個屬性和一個原型say方法。框架

這種寫法跟傳統的面嚮對象語言(好比 C++ 和 Java)差別很大。接下來咱們看下ES6 類的寫法,這個就很接近於傳統面嚮對象語言了。若是你想了解傳統面嚮對象語言,這裏是一個好切入點。dom

1.2 ES6 class類定義函數

class Person {
  constructor( name , age ) {
    this.name = name;
    this.age = age;
  }
  say() {
    return '我叫' + this.name + ',今年' + this.age + '歲';
  }
}
var  p = new Person('大彬哥',18);  // Person {name: "大彬哥", age: 18}
p.say()                           //"我叫大彬哥,今年18歲"

上面代碼定義了一個一樣的Person類,constructor方法就是構造方法,而this關鍵字則表明實例對象,這更接近傳統語言的寫法。工具

注意:學習

雖然引入了class關鍵字,但ES6中並無真的引入類這個概念,經過class定義的仍然是函數:this

console.log(typeof Person); // 'function'

因此說,class僅僅是經過更簡單直觀的語法去實現原型鏈繼承。這種對語言功能沒有影響、可是給程序員帶來方便的新語法,被稱爲語法糖。

圖片描述
2、類的傳參 constructor

在類的參數傳遞中咱們用constructor( )進行傳參。傳遞參數後能夠直接使用this.xxx進行調用。

class Person {
   constructor(a,b){
        this.a=a;
        this.b=b;
   }
   add(){
        return this.a + this.b;
   }
}
let p = new Person(18,30);
console.log(p.add());  // 48 (18+30)

咱們用constructor來傳遞參數,而後用了一個add方法,把參數相加。這和之前咱們的函數傳參方法有些不同,因此小夥伴們要注意轉換下思惟。

3、靜態方法

在面嚮對象語言中,靜態方法是指不須要實例化,能夠經過類名直接調用的方法,但靜態方法不會繼承到類實例中,所以靜態方法常常用來做爲工具函數。好比咱們常常用的Math.random(),咱們並不須要先new 一個Math而後再去用,一是若是做者那麼設計JS一來是不必,二是用起來太繁瑣。

在使用函數模擬類時,能夠像下面這樣定義靜態方法:

function Person(name, sex) {}

Person.walk = function() {
    console.log('我會走路')
}

Person.walk();  // 我會走路
var person = new Person();
person.walk();  // TypeError

在ES6 class類定義中,可使用static關鍵字定義:

class Person {
  constructor() {}

  static walk(){
      console.log('我會走路')
  }
}
Person.walk();  // 我會走路
var person = new Person();
person.walk();  // TypeError

static關鍵字是ES6的另外一個語法糖,static 使靜態方法聲明也成爲了一個一等公民。

於此同時,靜態方法也是能夠從子類中的super對象上調用的。

class Person {
  constructor() {}

  static walk(){
      return '我會走路'
  }
}

class People extends Person {
  static walk() {
    return super.walk() + ', 我還會跑步';
  }
}

People.walk();  //"我會走路, 我還會跑步"

4、封裝與繼承

封裝和繼承,是面向對象編程三大核心特徵中很是重要的兩個,封裝和繼承在咱們實際生活中也有很是多的應用。舉個例子,你去驢肉火燒店去吃飯。

老闆把驢肉面和火燒一塊兒買,起名字叫「精英驢火套餐」,這就是封裝。

而進去之後跟老闆說,老闆給我來個「82年的驢火套餐」這就是繼承。固然了你不只僅能繼承,還能擴展本身的功能。好比你能夠跟老闆說,老闆再給我加一個驢板腸。說的我都餓了,不過咱們仍是教編程的專欄,不是開店的專欄,咱們繼續,看看ES6裏面怎麼玩繼承。

4.1 extends

舊的原型繼承有時看起來讓人很是頭疼。

function Child(firstName, lastName, age) {
  Parent.call(this, firstName, lastName)
  this.age = age
}

Child.prototype = Object.create(Parent.prototype)
Child.constructor = Child

ES6中新的extends關鍵字解決了這個問題:

class Child extends Parent {}

上面代碼定義了一個Child類,該類經過extends關鍵字,繼承了Parent類的全部屬性和方法。

因爲沒有在Child內部寫任何代碼,因此這兩個類徹底同樣,等於複製了一個Parent類。

以後,咱們在Child內部加上代碼:

class Child extends Parent {
  constructor(firstName, lastName, age) {
    super(firstName, lastName)  
    // 調用父類的constructor(firstName, lastName)
    this.age = age
  }
  speak(){
    return this.age + ' ' + super.speak(); 
    // 調用父類的speak()
  }
}

使用簡介的 extends 達到繼承的目的,而非雜亂的 Object.create()、.proto、Object.setPrototypeOf(),這樣能讓咱們更順利的擴充功能。
圖片描述

4.2 super

super這個關鍵字,既能夠看成函數使用,也能夠看成對象使用。在這兩種狀況下,它的用法徹底不一樣。

(1)super做爲函數調用

表明父類的構造函數,ES6中規定,子類的構造函數必須執行一次super函數。

class A {}

class B extends A {
  constructor() {
    super();
  }
}

上面代碼中,子類B的構造函數之中的super(),表明調用父類的構造函數,這是必須的,不然 JavaScript 引擎會報錯。

注意,super雖然表明了父類A的構造函數,可是返回的是子類B的實例,即super內部的this指的是B,所以super()在這裏至關於A.prototype.constructor.call(this)。

(2)super做爲對象時,指向父類的原型對象。

class A {
  p() {
    return 2;
  }
}

class B extends A {
  constructor() {
    super();
    console.log(super.p()); // 2
  }
}

let b = new B();

與Java同樣,JavaScript也使用extends關鍵字實現繼承,子類中能夠經過super關鍵字調用父類:

在 constructor 裏面,super 的用法是 super()。它至關於一個函數,調用它等於調用父類的 constructor 。

但在普通方法裏面,super 的用法是 super.prop 或者 super.method(),它至關於一個指向對象的 [[Prototype]] 的屬性。

4.3 getter(取值函數)、 setter(存值函數)

與 ES5 同樣,在「類」的內部可使用get和set關鍵字,對某個屬性設置存值函數和取值函數,攔截該屬性的存取行爲。

class Person {
  constructor() {}
  get prop() {
    return 'getter';
  }
  set prop(value) {
    console.log('setter: '+value);
  }
}

let p = new Person();
p.prop = 666;   // setter: 666
p.prop           // 'getter'

5、總結

圖片描述

不管學什麼知識,最重要也是最基礎的,要實現思想上的轉變,目前大部分框架和庫,都採用了面向對象方式編程。並且在工做中,要書寫中型和大型的項目也常用面向對象方式編程,可能你們習慣了面向過程方式編程,其實面向對象方式編程一旦習慣了,會讓我開發和思路更寬闊和易於開發項目。

從學習javascript基礎開始的時候,咱們就瞭解了js中的保留字,js中並無用到,可是未來可能會用到的將來關鍵字。這些保留字中就包括:class、extends、super。這些就是爲未來在js中支持面向對象的類機制而預留的。

果不其然,如今ES6語法中使用到了這些保留字,這些保留字成功升級成了關鍵字,可見當時javascript的設計者仍是頗有前瞻眼光的。

經過這些新的關鍵字,使類成爲了JS中一個新的一等公民。可是目前爲止,這些關於類的新關鍵字僅僅是創建在舊的原型系統上的語法糖。這樣作的緣由是爲了保證向後兼容性。也就是,舊代碼能夠在不作任何hack的狀況下,與新代碼同時運行。

不過,它使代碼的可讀性變得更高,而且爲從此版本里更多面向對象的新特性打下了基礎。

相關文章
相關標籤/搜索