Javascript是一種基於對象(object-based)的語言,你遇到的全部東西幾乎都是對象。可是,它又不是一種真正的面向對象編程(OOP)語言,由於它的語法中沒有class(類)。摘自阮一峯老師語錄html
ES5的JavaScript中只有對象,想要模擬類去生成一個對象實例,只能經過定義一個構造函數,而後經過new操做符來完成。前端
let Animal = function (type) { this.type = type } Animal.prototype.walk = function () { console.log(`I am walking`) } let dog = new Animal('dog') let monkey = new Animal('monkey') //構造函數生成實例的執行過程 1.當使用了構造函數,而且new 構造函數(),後臺會隱式執行new Object()建立對象; 2.將構造函數的做用域給新對象,(即new Object()建立出的對象),而函數體內的this就表明new Object()出來的對象。 3.執行構造函數的代碼。 4.返回新對象(後臺直接返回);
ES6引入了Class(類)這個概念,經過class關鍵字能夠定義一個類node
class Animal { constructor (type) { this.type = type } walk () { console.log(`I am walking`) } } let dog = new Animal('dog') let monkey = new Animal('monkey')
可是Class的類型仍是function,而且console.log(Animal.prototype);結果幾乎是同樣的,因此能夠認爲class聲明類的方式是function聲明類方式的語法糖。甚至在class聲明類後仍可以使用ES5的方式來爲這個類添加,覆蓋方法。編程
console.log(typeof Animal); //function ES5中打印的console.log(Animal.prototype) //{eat: ƒ, constructor: ƒ} //eat: ƒ () //constructor: ƒ (type) //__proto__: Object ES6中打印的console.log(Animal.prototype) //{constructor: ƒ, eat: ƒ} //constructor: class Animal //eat: ƒ eat() //__proto__: Object 除了constructor後邊分別是f(type)和class Animal
class不存在變量提高,因此須要先定義再使用。由於ES6不會把類的聲明提高到代碼頭部,可是ES5就不同,ES5存在變量提高,能夠先使用,而後再定義。框架
//ES5能夠先使用再定義,存在變量提高 new A(); function A(){ } //ES6不能先使用再定義,不存在變量提高 會報錯 new B();//B is not defined class B{ }
類中的屬性,能夠直接在constructor中經過this直接定義,還能夠經過get/set直接在類的頂層定義函數
class Animal { constructor (type, age) { this.type = type this._age = age } get age () { return this._age } set age (val) { this._age = val } }
get能夠定義一個只讀屬性this
class Animal { constructor (type) { this.type = type } get addr () { return '北京動物園' } }
get/set能夠進行一些簡單封裝,以下prototype
class CustomHTMLElement { constructor (element) { this.element = element } get html () { return this.element.innerHTML } set html (value) { this.element.innerHTML = value } }
get/set還能夠模擬設置私有屬性,並能夠經過get和set對獲取屬性和讀取屬性進行一些邏輯判斷code
let _age = 4 class Animal{ constructor(type) { this.type = type } get age() { if(this.type == 'dog'){ return _age }else{ return "I don't know" } } set age(val){ if(val<7&&val>4){ _age = val } } eat () { console.log('i am eat food') } } let dog = new Animal('dog') let cat = new Animal('cat') console.log(dog.age)//4 console.log(cat.age)//I don't know 在get age中只有dog能拿到_age dog.age = 6 console.log(dog.age)//6 dog.age = 8 console.log(dog.age)//6 在set age中傳入參數必須小於7大於4才能生效
ES5中繼承的實現htm
// 定義父類 let Animal = function (type) { this.type = type } // 定義方法 Animal.prototype.walk = function () { console.log(`I am walking`) } // 定義靜態方法 Animal.eat = function (food) { console.log(`I am eating`) } // 定義子類 let Dog = function () { // 初始化父類 Animal.call(this, 'dog') this.run = function () { console.log('I can run') } } // 繼承 Dog.prototype = Animal.prototype
ES6中經過extends關鍵字實現繼承。
子類必須在constructor方法中調用super方法,以後才能使用this關鍵字,不然新建實例時會報錯。這是由於子類沒有本身的this對象,而是繼承父類的this對象。若是不調用super方法,子類就得不到this對象。在這一點上ES5的繼承與ES6正好相反,ES5先建立本身的this對象而後再將父類的屬性方法添加到本身的this當中。
若是子類沒有顯式的定義constructor,那麼下面的代碼將被默認添加(不信能夠嘗試下,哈)。換言之,若是constructor函數中只有super的話,該constructor函數能夠省略。
class Animal { constructor (type) { this.type = type } walk () { console.log(`I am walking`) } static eat () { console.log(`I am eating`) } } class Dog extends Animal { constructor () { super('dog') } run () { console.log('I can run') } }
靜態方法是面向對象最經常使用的功能,在ES5中利用function實現的類是這樣實現一個靜態方法的
let Animal = function (type) { this.type = type this.walk = function () { console.log(`I am walking`) } } Animal.eat = function (food) { console.log(`I am eating`); }
在ES6中使用static的比納基是否是靜態方法
class Animal { constructor (type) { this.type = type } walk () { console.log(`I am walking`) } static eat () { console.log(`I am eating`) } }
靜態方法不須要實例化能夠直接經過類調用
class Animal{ static a(){ return "我是Animal類中的,實例方法,無須實例化,能夠直接調用" } } //經過類名直接調用 console.log(Animal.a());//我是Animal類中的,實例方法,無須實例化,可直接調用!
靜態方法只能在靜態方法中調用,不能在實例方法中調用
class Animal{ static a(){ return "我只容許被靜態方法調用哦!" } static b(){ //經過靜態方法b來調用靜態方法a console.log(this.a()); } } Animal.b();//輸出:我只容許被靜態方法調用
經過實例方法來調用靜態方法會報錯
class Animal{ static a(){ return "我只容許被靜態方法調用哦!" } b(){ console.log(this.a());//TypeError: this.a is not a function } } var obj=new Animal(); obj.b(); //其餘地方想要調用靜態方法可藉助類來調用,如使用Animal.b() class Animal{ static a(){ return "我只容許被靜態方法調用哦!" } static b(){ //經過靜態方法b來調用靜態方法a console.log(this.a()); } c(){ console.log(Animal.b()) } } Animal.b();//輸出:我只容許被靜態方法調用 let dog = new Animal() Animal.c()////輸出:我只容許被靜態方法調用
父類的靜態方法,能夠被子類繼承
class Animal { static a() {//父類Animal的靜態方法 return '我是父類的靜態方法a'; } } class Dog extends Animal {} //子類Dog能夠直接調用父類的靜態方法a console.log(Dog.a());
想經過子類的靜態方法調用父類的靜態方法,須要從super對象上調用
class Animal { static a() { return '我是經過super來調取出來的'; } } class Dog extends Animal { static a(){ return super.a(); } } console.log(Dog.a()); //我是經過super來調取出來的
靜態屬性指的是 Class 自己的屬性, 即Class.propname, 而不是定義在實例對象( this) 上的屬性。
class Animal{ constructor(){ this.name="實例屬性" } } Animal.prop1="靜態屬性1"; Animal.prop2="靜態屬性2"; console.log(Animal.prop1,Animal.prop2);//靜態屬性1 靜態屬性2
前端各類框架起飛,基本不須要去使用類來實現或者完善前端頁面功能,在服務端寫node.js的話可能會常常使用類語法。
下方代碼是用類實如今同一個頁面設置多個分頁列表。(這個功能多數UI框架也解決了。。。)
class PageUtil{ constructor(pageNo,pageSize,total){ //構造初始變量 this.pageNo = pageNo; //起始頁面 this.pageSize = pageSize //一頁數據條數 this.total = total //數據總數 this.currentPage = 0 //當前選中頁數 this.pageTotal = Math.ceil(this.total/this.pageSize) //總頁數 } nextPage(){ //下一頁 if(this.currentPage < this.pageTotal){ this.currentPage++ } } beforePage(){ //上一頁 if(this.currentPage > 1){ this.currentPage-- } } jumpPage(page){ //跳頁 this.currentPage = page } changePageSize(pageSize){ //改變頁大小 this.pageSize = pageSize this.pageTotal = Math.ceil(this.total/this.pageSize) //總頁數 } getTotalPage(){ //獲取總頁數 return Math.ceil(this.total/this.pageSize) } } class DialogPage extends PageUtil{ //繼承PageUtil類 constructor(pageNo,pageSize,total,pageTotal){ super(pageNo,pageSize,total) this.pageTotal = pageTotal } getTotalPage(){ return this.pageTotal || super.getTotalPage() //重寫getTotalPage方法 } } const contentPage = new PageUtil(1,10,100) //實例化2個pageUtil對象 contentPage.getTotalPage() console.log(contentPage.currentPage) contentPage.nextPage() console.log(contentPage.currentPage) const dialogPage = new DialogPage(1,10,100,10) console.log(dialogPage.currentPage) dialogPage.getTotalPage()
實現一個類具備Push,PoP功能
class Myarray { constructor(arr) { this.arr = arr; } myPop() { if (this.arr.length === 0) return undefined; return Number(this.arr.splice(this.arr.length - 1, 1)) } myPush() { let _this = this; Array.from(arguments, el => _this.arr.splice(_this.arr.length, 0, el)) return this.arr.length; } } let arr = Array.of(1, 5, 6, 7, 8) let myArray = new Myarray(arr); console.log(myArray.myPop(), arr) console.log(myArray.myPush(null), arr)