ES6-10筆記(二)

class類

Javascript是一種基於對象(object-based)的語言,你遇到的全部東西幾乎都是對象。可是,它又不是一種真正的面向對象編程(OOP)語言,由於它的語法中沒有class(類)。摘自阮一峯老師語錄html

class聲明

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{

}

Setters&Getters

類中的屬性,能夠直接在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')
  }
}

靜態方法 static Methods&靜態屬性

靜態方法是面向對象最經常使用的功能,在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)
相關文章
相關標籤/搜索