在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的狀況下,與新代碼同時運行。
不過,它使代碼的可讀性變得更高,而且爲從此版本里更多面向對象的新特性打下了基礎。